Skip to content

Commit 95cc0c2

Browse files
committed
feat(algorithms, hash-table): ransom note
1 parent b0cd89c commit 95cc0c2

24 files changed

+197
-18
lines changed

algorithms/hash_table/__init__.py

Whitespace-only changes.
File renamed without changes.
File renamed without changes.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Ransom Note
2+
3+
Given two strings, ransom_note and magazine, check if ransom_note can be constructed using the letters from magazine.
4+
Return TRUE if it can be constructed, FALSE otherwise.
5+
6+
> Note: A ransom note is a written message that can be constructed by using the letters available in the given magazine.
7+
> The magazine can have multiple instances of the same letter. Each instance of the letter in the magazine can only be
8+
> used once to construct the ransom note.
9+
10+
## Constraints
11+
12+
- 1 <= `ransom_note.length`, `magazine.length` <= 10^3
13+
- The `ransom_note` and `magazine` consist of lowercase English letters
14+
15+
## Examples
16+
17+
![Example 1](./images/examples/ransom_note_example_1.png)
18+
![Example 2](./images/examples/ransom_note_example_2.png)
19+
![Example 3](./images/examples/ransom_note_example_3.png)
20+
![Example 4](./images/examples/ransom_note_example_4.png)
21+
22+
## Topics
23+
24+
- Hash Table
25+
- String
26+
- Counting
27+
28+
## Solution
29+
An optimized approach to solve this problem is to keep track of the occurrences of characters using the hash map. We
30+
store the frequency of each character of the magazine in the hash map. After storing the frequencies, we iterate over
31+
each character in the ransom note and check if the character is present in the hash map and its frequency is greater
32+
than zero. If it is, we decrement the frequency by 1, indicating that we’ve used that character to construct the ransom
33+
note. If the character is not present in the hash map or its frequency is 0, we immediately return FALSE since it's
34+
impossible to construct the ransom note.
35+
36+
If we successfully iterate through all characters in the ransom note without encountering a character that is not present
37+
in the hash map or its frequency is 0, we return TRUE, indicating that we can construct the ransom note from the
38+
characters available in the magazine.
39+
40+
![Solution 1](./images/solutions/ransom_note_solution_1.png)
41+
![Solution 2](./images/solutions/ransom_note_solution_2.png)
42+
![Solution 3](./images/solutions/ransom_note_solution_3.png)
43+
![Solution 4](./images/solutions/ransom_note_solution_4.png)
44+
![Solution 5](./images/solutions/ransom_note_solution_5.png)
45+
![Solution 6](./images/solutions/ransom_note_solution_6.png)
46+
![Solution 7](./images/solutions/ransom_note_solution_7.png)
47+
![Solution 8](./images/solutions/ransom_note_solution_8.png)
48+
![Solution 9](./images/solutions/ransom_note_solution_9.png)
49+
![Solution 10](./images/solutions/ransom_note_solution_10.png)
50+
![Solution 11](./images/solutions/ransom_note_solution_11.png)
51+
52+
### Summary
53+
54+
- Create a hash map to store the frequencies of each character in the magazine.
55+
- Iterate through each character in the ransom note and check the following conditions:
56+
- If the character is not in the hash map or the frequency of the character is 0, return FALSE
57+
- Otherwise, decrement the frequency of the character in the hash map by 1.
58+
- Return TRUE if we successfully iterate through all characters in the ransom note.
59+
60+
### Time Complexity
61+
62+
The time complexity of this solution is O(n+m), where n is the length of the ransom note and m is the length of the
63+
magazine.
64+
65+
### Space Complexity
66+
67+
The space complexity of this solution is O(1) because we have a constant number of lowercase English letters
68+
(26 unique characters). Therefore, the space required by the hash map will remain constant.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from collections import Counter
2+
3+
4+
def can_construct(ransom_note: str, magazine: str) -> bool:
5+
"""
6+
Checks if it is possible to construct a ransom note from the given letters in the magazine where each letter in the
7+
magazine can only be used once. If a letter in the magazine occurs more than once, it can only be used that many
8+
number of times, so `magazine=aabc`, means we can use letter a twice, but not more than that.
9+
10+
Complexity Analysis:
11+
12+
Time O(n + m): Where n is the number of letters in `ransom_note` and `m` is the number of letters in `magazine`. This
13+
is because we iterate through the magazine to count occurrences of the number of letters and again through ransom_note
14+
to check if each letter is present in the magazine
15+
16+
Space O(1): Since there are only English letters which are 26, the space used by the hash table is always count going
17+
to be constant.
18+
19+
Args:
20+
ransom_note(str): the string with which we intend to construct from the magazine.
21+
magazine(str): the string with which we intend to use to construct ransom_note
22+
Returns:
23+
bool: True if we can construct ransom note from the magazine, false otherwise.
24+
"""
25+
# No need to proceed if we don't have a magazine to construct a ransom note from
26+
if not magazine:
27+
return False
28+
29+
# Count the number of occurrences of each letter in the magazine. This will be used to keep track of the number of
30+
# letters we can use when constructing the ransom note
31+
occurrences = Counter(magazine)
32+
# Count the number of letters in the ransom note. This will be used to track how many letters are left when constructing
33+
# the ransom note from the letters in the magazine
34+
count = len(ransom_note)
35+
36+
# Iterate through each letter in the ransom note to check if it is in the magazine
37+
for letter in ransom_note:
38+
# If a letter does not exist in the frequency map of the magazine or the count has now become 0 meaning we can't
39+
# use the letter from the magazine, then there is no need to proceed with the iteration, we can't construct
40+
# the ransom note
41+
if letter not in occurrences or occurrences[letter] == 0:
42+
return False
43+
44+
# if the letter is in the occurrences, we decrease the count of the occurrences of the letter and the number
45+
# of letters left to construct the ransom note
46+
occurrences[letter] -= 1
47+
count -= 1
48+
49+
# If we have no letters left, then we can construct the ransom note from the letters, else we can't so, we check to
50+
# see if the count equals 0
51+
return count == 0
52+
53+
54+
def can_construct_2(ransom_note: str, magazine: str) -> bool:
55+
# create an empty hash map to store the frequency of each character in the magazine string
56+
frequency = {}
57+
58+
for char in magazine:
59+
# if character is already present in hash map then increment
60+
# its frequency by 1
61+
if char in frequency:
62+
frequency[char] += 1
63+
64+
# else count its first occurrence
65+
else:
66+
frequency[char] = 1
67+
68+
for char in ransom_note:
69+
70+
# if the character is not in the hash map or its count is 0, return False
71+
if char not in frequency or frequency[char] == 0:
72+
return False
73+
74+
# otherwise, decrease the character's frequency in the hash map by 1
75+
else:
76+
frequency[char] -= 1
77+
78+
return True
18.9 KB
Loading
15.7 KB
Loading
16.7 KB
Loading
17.1 KB
Loading
24.8 KB
Loading

0 commit comments

Comments
 (0)