{x}
blog image

Ransom Note

Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.

Each letter in magazine can only be used once in ransomNote.

 

Example 1:

Input: ransomNote = "a", magazine = "b"
Output: false

Example 2:

Input: ransomNote = "aa", magazine = "ab"
Output: false

Example 3:

Input: ransomNote = "aa", magazine = "aab"
Output: true

 

Constraints:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNote and magazine consist of lowercase English letters.

Solution Explanation: Ransom Note

The problem asks whether a ransomNote can be constructed using characters from magazine, with each character in magazine usable only once. The optimal solution involves using a hash table (or an array as a simpler hash table for this specific case) to efficiently count character frequencies.

Approach:

  1. Character Counting in Magazine: First, we count the occurrences of each character (a-z) in the magazine string. We can use an array of size 26 (one for each lowercase letter) or a hash map (dictionary in Python) for this. The array approach is generally more efficient in this scenario due to its constant-time access.

  2. Checking Ransom Note: We iterate through the ransomNote. For each character:

    • We decrement its count in our character count array/hash map.
    • If the count becomes negative, it means we've used more of that character than available in the magazine. We immediately return false.
  3. Success: If we complete the iteration without finding any negative counts, it means we can construct the ransomNote using characters from magazine. We return true.

Time and Space Complexity:

  • Time Complexity: O(m + n), where 'm' is the length of ransomNote and 'n' is the length of magazine. We iterate through both strings once. The array access (or hash map lookup) is considered O(1) on average.

  • Space Complexity: O(1). We use a fixed-size array of size 26 to store character counts. The space usage doesn't depend on the input string lengths (it's constant).

Code Examples (with explanations):

The provided code snippets across multiple languages all follow the same fundamental algorithm:

Python:

from collections import Counter
 
class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        cnt = Counter(magazine) #Efficient character counting using Counter
        for c in ransomNote:
            cnt[c] -= 1
            if cnt[c] < 0:
                return False
        return True

Java:

class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int[] cnt = new int[26]; //Array to store character counts
        for (char c : magazine.toCharArray()) { //Iterate and count
            cnt[c - 'a']++; 
        }
        for (char c : ransomNote.toCharArray()) { //Check ransom note
            if (--cnt[c - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
}

C++:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int cnt[26] = {}; //Array initialization (all elements set to 0)
        for (char c : magazine) {
            cnt[c - 'a']++;
        }
        for (char c : ransomNote) {
            if (--cnt[c - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
};

The other languages (Go, TypeScript, C#, PHP) demonstrate similar logic, adapting the syntax to each language's specifics, but maintaining the core algorithm of counting characters in magazine and then checking against ransomNote. The key is the efficient use of an array (or hash map in languages where that's more natural) for constant-time lookups of character frequencies.