Ransom Note
Ransom Note: Mastering Frequency Counting
Welcome back to codinginterview.net. If you have been following our curriculum, you are getting comfortable with pointers and search spaces. Now, it is time to master one of the most foundational concepts in technical interviews: Hash Maps and Frequency Counting. The "Ransom Note" problem is a classic gauge of whether a candidate understands how to track and look up data in constant time. By the end of this guide, using arrays and hash maps as high-speed inventory systems will be second nature to you.
1. Understanding the Problem
You are given two strings: ransomNote and magazine. Your task is to determine if you can construct the ransomNote using the letters provided in the magazine. If you can, return True. If you cannot, return False.
The Core Constraint (The Trap):
Just like making a physical ransom note by cutting letters out of a magazine, each letter in the magazine can only be used once. If your ransom note requires three 'a's, but the magazine only has two, you must return False. Additionally, string manipulation (like deleting characters from a string) in most languages creates entirely new strings in memory, which can silently destroy your performance.
2. The Naive Approach: Search and Destroy
The most intuitive way to solve this is to iterate through each character in your ransomNote and search for it in the magazine string. If you find the character, you remove it from the magazine (to ensure it isn't used again) and move on to the next letter.
Trade-off Analysis
While this logic works, it is mathematically expensive:
- Time Complexity: O(N * M) — For every character in the ransom note (N), you potentially scan the entire magazine (M). Furthermore, deleting a character from a string often takes O(M) time on its own, making this highly inefficient.
- Space Complexity: O(M) — Because strings are immutable in languages like Python and Java, "removing" a character actually means creating a brand-new string in memory every single time.
3. The Optimal Approach: The Frequency Array (O(N + M) Time)
To pass a senior-level technical interview, we must avoid nested loops and string recreation. We can achieve this by treating the magazine as an inventory. We will use a Frequency Map (or better yet, a simple fixed-size Array) to count exactly how many of each letter we have available.
Imagine running a bakery. Before you bake a large order (the ransom note), you first go to your pantry (the magazine) and count all your ingredients on a clipboard (the array). Then, you look at your recipe. For each ingredient required, you cross one off the clipboard. If you ever need an ingredient but the clipboard says you have 0 left, you immediately know the order cannot be completed.
Since the problem typically guarantees that both strings only contain lowercase English letters, we don't even need a heavy Hash Map. A simple array of size 26 (representing 'a' through 'z') is perfectly sufficient and lightning fast.
4. The Logic Step-by-Step
- Initial Check: If the
ransomNoteis longer than themagazine, it is physically impossible to construct. ReturnFalseimmediately. - Build the Inventory: Create an integer array of size 26, filled with zeros.
- Stock the Pantry: Iterate through every character in the
magazine. Convert each character to its alphabetical index ('a' = 0, 'b' = 1, etc.) and increment the value at that index in your array. - Consume the Inventory: Iterate through every character in the
ransomNote. Convert each character to its index and decrement the value in your array.- The Check: If, after decrementing, the value at that index drops below 0, it means you needed a letter you didn't have. Return
Falseimmediately.
- The Check: If, after decrementing, the value at that index drops below 0, it means you needed a letter you didn't have. Return
- If you successfully iterate through the entire
ransomNotewithout returning false, you have all the required letters. ReturnTrue.
5. Complexity Analysis
- Time Complexity: O(N + M) — We iterate through the
magazinestring (M) once, and theransomNotestring (N) once. Array lookups take O(1) time. This gives us a highly optimal linear time complexity. - Space Complexity: O(1) — We use an array of exactly 26 integers. Because this size never grows regardless of how large the input strings are, the space complexity is strictly constant.
6. Code Implementations
Expand the sections below to see the optimal O(1) space "Frequency Array" implementations across different languages.
View Python Solution
class Solution:
def canConstruct(self, ransomNote: str, magazine: str) -> bool:
if len(ransomNote) > len(magazine):
return False
# Initialize an array of 26 zeros for 'a' through 'z'
char_counts = [0] * 26
# Stock the inventory
for char in magazine:
index = ord(char) - ord('a')
char_counts[index] += 1
# Consume the inventory
for char in ransomNote:
index = ord(char) - ord('a')
char_counts[index] -= 1
# If we used a letter we don't have, return False
if char_counts[index] < 0:
return False
return True
View Java Solution
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length()) {
return false;
}
// Array to store counts of 26 lowercase English letters
int[] charCounts = new int[26];
// Stock the inventory from the magazine
for (char c : magazine.toCharArray()) {
charCounts[c - 'a']++;
}
// Consume the inventory using the ransom note
for (char c : ransomNote.toCharArray()) {
charCounts[c - 'a']--;
// If the count drops below zero, we are missing a letter
if (charCounts[c - 'a'] < 0) {
return false;
}
}
return true;
}
}
View C++ Solution
#include <string>
#include <vector>
class Solution {
public:
bool canConstruct(std::string ransomNote, std::string magazine) {
if (ransomNote.length() > magazine.length()) {
return false;
}
// Initialize vector of 26 elements with 0
std::vector<int> charCounts(26, 0);
// Build the frequency map
for (char c : magazine) {
charCounts[c - 'a']++;
}
// Check against the ransom note
for (char c : ransomNote) {
charCounts[c - 'a']--;
if (charCounts[c - 'a'] < 0) {
return false;
}
}
return true;
}
};
7. Conclusion: You Are Ready
Congratulations, you have just mastered the Frequency Counting pattern! While a standard Hash Map (like a dictionary in Python) is a great tool, recognizing that a limited character set (like 26 English letters) allows you to use a fixed-size array is a powerful optimization that impresses interviewers. It proves you understand the underlying mechanics of memory management and algorithmic overhead. Keep this "inventory clipboard" mental model in your toolkit, as it is the exact same logic used to solve complex problems like Anagrams and Sliding Window string questions!