Group Anagrams Using Hash Map in DSA Rust - Time & Space Complexity
We want to understand how long it takes to group words that are anagrams using a hash map.
How does the time grow when we have more words or longer words?
Analyze the time complexity of the following code snippet.
use std::collections::HashMap;
fn group_anagrams(strs: Vec) -> Vec> {
let mut map: HashMap> = HashMap::new();
for s in strs {
let mut chars: Vec = s.chars().collect();
chars.sort_unstable();
let key: String = chars.into_iter().collect();
map.entry(key).or_default().push(s);
}
map.into_values().collect()
}
This code groups words that are anagrams by sorting each word and using the sorted word as a key in a hash map.
- Primary operation: Loop over all words and sort each word's characters.
- How many times: Once for each word in the input list.
As the number of words grows, the code sorts each word, so the time depends on both the number of words and their length.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 words, length 5 | About 10 x 5 log 5 ≈ 10 x 11.6 = 116 operations |
| 100 words, length 5 | About 100 x 5 log 5 ≈ 100 x 11.6 = 1160 operations |
| 1000 words, length 5 | About 1000 x 5 log 5 ≈ 1000 x 11.6 = 11600 operations |
Pattern observation: The time grows roughly linearly with the number of words and also depends on the length of each word times its log.
Time Complexity: O(n * k log k)
This means the time grows with the number of words (n) and the time to sort each word of length k.
[X] Wrong: "Sorting each word is constant time, so the whole process is just O(n)."
[OK] Correct: Sorting depends on word length, so longer words take more time. Ignoring this misses an important part of the cost.
Understanding how sorting each word affects the total time helps you explain your solution clearly and shows you know what matters when handling many or long words.
What if we used a character count array as the key instead of sorting? How would the time complexity change?
Practice
Solution
Step 1: Understand anagram grouping
Anagrams have the same letters in different orders, so sorting letters gives a common key.Step 2: Use sorted string as hash map key
By sorting each word and using it as a key, all anagrams map to the same key and group together.Final Answer:
Use sorted strings as keys to group words with the same letters -> Option DQuick Check:
Sorted string key groups anagrams [OK]
- Grouping by word length only
- Using first letter as key
- Not sorting letters before grouping
Solution
Step 1: Identify correct hash map type
We need keys as sorted strings and values as vectors of strings to hold grouped anagrams.Step 2: Match Rust syntax for hash map
HashMap correctly maps sorted keys to lists of words.Final Answer:
let mut map: HashMap = HashMap::new(); -> Option AQuick Check:
HashMap with String keys and Vec<String> values [OK]
- Using Vec instead of HashMap
- Wrong value type (String instead of Vec<String>)
- Incorrect key type (i32 instead of String)
use std::collections::HashMap;
fn group_anagrams(words: Vec<&str>) -> Vec {
let mut map: HashMap = HashMap::new();
for word in words {
let mut chars: Vec<char> = word.chars().collect();
chars.sort_unstable();
let key = chars.into_iter().collect::<String>();
map.entry(key).or_default().push(word.to_string());
}
map.into_values().collect()
}
fn main() {
let input = vec!["eat", "tea", "tan", "ate", "nat", "bat"];
let result = group_anagrams(input);
println!("{:?}", result);
}Solution
Step 1: Sort each word to create keys
"eat", "tea", "ate" all sort to "aet"; "tan", "nat" to "ant"; "bat" to "abt".Step 2: Group words by sorted keys
Words with same sorted key are grouped: ["eat", "tea", "ate"], ["tan", "nat"], ["bat"].Final Answer:
[["eat", "tea", "ate"], ["tan", "nat"], ["bat"]] -> Option CQuick Check:
Sorted keys group anagrams [OK]
- Not sorting letters before grouping
- Grouping single words separately
- Mixing order of groups incorrectly
use std::collections::HashMap;
fn group_anagrams(words: Vec<&str>) -> Vec {
let mut map: HashMap = HashMap::new();
for word in words {
let mut chars: Vec<char> = word.chars().collect();
chars.sort(); // Bug here
let key = chars.into_iter().collect::<String>();
map.entry(key).or_default().push(word.to_string());
}
map.into_values().collect()
}Solution
Step 1: Identify sorting method issue
Using chars.sort() works but sort_unstable() is preferred for primitive types like char for speed.Step 2: Explain why sort_unstable() is better
sort_unstable() is faster and sufficient here because order stability is not needed for grouping anagrams.Final Answer:
Use sort_unstable() instead of sort() for better performance -> Option AQuick Check:
sort_unstable() improves sorting speed [OK]
- Using sort() unnecessarily slowing code
- Changing iterator type incorrectly
- Ignoring case sensitivity issues
Solution
Step 1: Normalize words by removing spaces and converting to lowercase
To group anagrams ignoring case and spaces, clean words by removing spaces and making all letters lowercase.Step 2: Sort letters of normalized words and use as keys
After normalization, sort letters to get keys that group all anagrams regardless of case or spaces.Final Answer:
Convert words to lowercase and remove spaces before sorting letters -> Option BQuick Check:
Normalize words before sorting for correct grouping [OK]
- Not normalizing case and spaces
- Using length or first letter as key
- Sorting original words without cleaning
Ready to prove it?
Pass the test and this pattern moves unknown
