LeetCode 383: Ransom Note
A simple and efficient solution to verify if a ransom note can be constructed from a magazine using HashMaps in Kotlin.
The Ransom Note problem is a classic example of frequency counting. It asks whether we can construct a specific string (ransomNote) using the characters available in another string (magazine). Each character in the magazine can only be used once.
In this post, we’ll solve LeetCode 383 using a HashMap to track character counts.
The Problem
Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.
Example:
1
2
Input: ransomNote = "aa", magazine = "aab"
Output: true
1
2
Input: ransomNote = "aa", magazine = "ab"
Output: false
Approach: Frequency Counting
The core logic is simple: for every character needed in the ransomNote, we must have a corresponding “available” character in the magazine.
- Count Availability: Iterate through the
magazinestring and count the frequency of each character. AHashMap<Char, Int>is perfect for this. - Consume Characters: Iterate through the
ransomNote. For each character:- Check if it exists in our map with a count $> 0$.
- If yes, decrement the count (use up the character).
- If no (or count is 0), return
falseimmediately because we don’t have enough letters.
- Success: If we finish checking the
ransomNotewithout running out of characters, returntrue.
The Code
Here is the Kotlin implementation using a HashMap:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
object LeetCode_383_Ransome_Note {
fun canConstruct(ransomNote: String, magazine: String): Boolean {
val table = HashMap<Char, Int>()
// Step 1: Build frequency map of the magazine
for(char in magazine) {
table[char] = table.getOrDefault(char, 0) + 1
}
// Step 2: Check if ransomNote can be formed
for(char in ransomNote) {
val count = table.getOrDefault(char, 0)
if (count == 0) {
return false // Not enough characters
} else {
table[char] = count - 1 // Use one character
}
}
return true
}
}
Optimization Tip
While a HashMap is a great general-purpose solution, if we know the input strings only contain lowercase English letters, we can use an Integer Array of size 26 instead. This avoids the overhead of hashing and is generally faster.
1
2
3
4
5
6
7
// Array-based approach (Space Optimization)
val counts = IntArray(26)
for (c in magazine) counts[c - 'a']++
for (c in ransomNote) {
if (counts[c - 'a'] == 0) return false
counts[c - 'a']--
}
Complexity Analysis
| Metric | Complexity | Explanation |
|---|---|---|
| Time | $O(m + n)$ | We iterate through the magazine ($m$) once and the ransomNote ($n$) once. |
| Space | $O(1)$ | Although we use a map, the number of unique characters is constant (e.g., 26 lowercase English letters), so the space complexity is technically constant. |
Source Code
🚀 Code: All the code for this tutorial is available in my DSA-Kotlin Repository.