AlgoMaster Logo

Ransom Note

Last Updated: April 6, 2026

easy
4 min read

Understanding the Problem

At its core, this is a character availability problem. We have a "supply" of letters (the magazine) and a "demand" for letters (the ransom note). For every character the ransom note needs, the magazine must have at least that many copies available.

The key constraint is that each magazine letter can only be used once. So if the ransom note needs three 'a's, the magazine must contain at least three 'a's. We need to verify this for every letter in the ransom note.

This boils down to: does the character frequency of the ransom note fit within the character frequency of the magazine?

Key Constraints:

  • 1 <= ransomNote.length, magazine.length <= 10^5 → With up to 100,000 characters, an O(m * n) brute force might be tight but an O(m + n) solution is comfortable.
  • ransomNote and magazine consist of lowercase English letters → Only 26 possible characters. This means we can use a fixed-size array of length 26 instead of a hash map, giving us true O(1) space.

Approach 1: Brute Force (Search and Remove)

Intuition

The most straightforward way to think about this: go through the ransom note letter by letter. For each letter, search the magazine for a matching letter. If you find one, cross it out (remove it so it can't be reused). If you can't find a match, the ransom note can't be constructed.

This mimics how you'd physically cut letters out of a magazine to compose a note.

Algorithm

  1. Convert the magazine string into a mutable structure (like a list of characters or a StringBuilder).
  2. For each character in the ransom note:
    1. Search the magazine for this character.
    2. If found, remove that character from the magazine (so it can't be reused).
    3. If not found, return false.
  3. If we process every ransom note character successfully, return true.

Example Walkthrough

ransomNote
1Process each character of ransomNote against magazine
0
a
1
a
2
b
magazine (mutable list)
1Convert magazine to mutable list: [a, a, b, c, d]
[a, a, b, c, d]
1/8

Code

For every character in the ransom note, we're scanning the entire magazine to find a match. When both strings are close to 10^5 characters, that's up to 10^10 operations. What if we sorted both strings so identical characters were grouped together?

Approach 2: Sorting + Two Pointers

Intuition

If we sort both strings, all identical characters are grouped together. Then we can walk through both sorted strings simultaneously with two pointers, checking if the magazine has enough of each character.

Think of it like lining up two sorted lists side by side. As long as every character the ransom note needs appears at least as many times in the magazine, we're good.

Algorithm

  1. Sort both ransomNote and magazine by character.
  2. Initialize two pointers: i for the ransom note, j for the magazine.
  3. While both pointers are within bounds:
    1. If ransomNote[i] == magazine[j], we've matched a character. Move both pointers forward.
    2. If ransomNote[i] > magazine[j], the magazine character is too small. Move j forward to find a match.
    3. If ransomNote[i] < magazine[j], the ransom note needs a character the magazine doesn't have. Return false.
  4. If we've matched all characters in the ransom note (i reached the end), return true. Otherwise, return false.

Example Walkthrough

sorted ransomNote
1After sorting: ransomNote = "aab", magazine = "aabcd"
0
a
1
a
2
b
sorted magazine
1Sorted magazine: "aabcd"
0
a
1
a
2
b
3
c
4
d
1/5

Code

Sorting both strings costs O(m log m + n log n), and we haven't even started comparing yet. But we don't actually need the characters in order. All we need is a count of how many times each character appears. Can we get those counts in a single pass?

Approach 3: Counting Array (Optimal)

Intuition

Since we only care about whether the magazine has enough of each letter, we can skip sorting entirely. Just count how many times each character appears in the magazine, then check if the ransom note's character demands are met.

Here's the neat part: since the input only has lowercase English letters, there are exactly 26 possible characters. We can use a simple integer array of size 26 instead of a hash map. This gives us constant space and avoids any hashing overhead.

The approach works in two passes: first, count the supply (magazine characters). Then, check the demand (ransom note characters) against the supply.

Algorithm

  1. Create an integer array count of size 26, initialized to zeros.
  2. For each character in the magazine, increment count[c - 'a'].
  3. For each character in the ransom note, decrement count[c - 'a'].
  4. If any count drops below zero, the magazine doesn't have enough of that character. Return false.
  5. If we process all ransom note characters without going negative, return true.

Example Walkthrough

magazine
1Start: ransomNote = "aa", magazine = "aab", count = [0]*26
0
a
1
a
2
b
ransomNote
1ransomNote = "aa"
0
a
1
a
count (showing non-zero only)
1Initialize count array of size 26, all zeros
1/6

Code