Frequency Counter Pattern Using Hash Map in DSA Go - Time & Space Complexity
We want to understand how fast counting item frequencies using a hash map works.
How does the time needed grow as the list gets bigger?
Analyze the time complexity of the following code snippet.
func frequencyCounter(arr []int) map[int]int {
freq := make(map[int]int)
for _, val := range arr {
freq[val]++
}
return freq
}
This code counts how many times each number appears in the list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Looping through the array once.
- How many times: Exactly once for each item in the array.
As the list gets bigger, the code does more counting steps, one per item.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 steps |
| 100 | About 100 steps |
| 1000 | About 1000 steps |
Pattern observation: The number of steps grows directly with the number of items.
Time Complexity: O(n)
This means the time needed grows in a straight line with the size of the input list.
[X] Wrong: "Counting frequencies takes more than one pass or nested loops."
[OK] Correct: The hash map lets us count in just one pass, so no extra loops are needed.
Knowing how to count frequencies quickly is a key skill that helps solve many problems efficiently.
"What if we used a sorted array instead of a hash map? How would the time complexity change?"
Practice
Solution
Step 1: Understand the role of a hash map
A hash map stores key-value pairs, allowing quick lookup and update of counts.Step 2: Apply to Frequency Counter Pattern
We use the hash map to keep track of how many times each item appears by incrementing counts.Final Answer:
To count how many times each item appears in a collection -> Option AQuick Check:
Frequency counting = counting items [OK]
- Thinking hash map sorts items
- Confusing frequency counting with removing duplicates
- Assuming hash map reverses order
Solution
Step 1: Identify correct map initialization syntax
In Go, make(map[string]int) creates a map with string keys and int values.Step 2: Check other options
freq := map[int]string{} reverses key-value types, C and D create slices, not maps.Final Answer:
freq := make(map[string]int) -> Option BQuick Check:
Correct map syntax = make(map[string]int) [OK]
- Using slices instead of maps
- Swapping key and value types
- Forgetting to use make() for map initialization
package main
import "fmt"
func main() {
words := []string{"apple", "banana", "apple", "orange", "banana", "apple"}
freq := make(map[string]int)
for _, w := range words {
freq[w]++
}
fmt.Println(freq["apple"])
}Solution
Step 1: Count occurrences of "apple" in the slice
"apple" appears at indices 0, 2, and 5, total 3 times.Step 2: Check frequency map update and print
freq[w]++ increments count for each word; freq["apple"] is 3.Final Answer:
3 -> Option CQuick Check:
Count of "apple" = 3 [OK]
- Counting unique words instead of occurrences
- Off-by-one errors in counting
- Printing wrong key frequency
package main
import "fmt"
func main() {
nums := []int{1, 2, 2, 3, 1}
freq := make(map[int]int)
for i := 0; i <= len(nums); i++ {
freq[nums[i]]++
}
fmt.Println(freq)
}Solution
Step 1: Check loop boundary conditions
Loop uses i <= len(nums), which causes index out of range error because last index is len(nums)-1.Step 2: Correct loop condition
Change to i < len(nums) to avoid accessing invalid index.Final Answer:
Loop condition should be i < len(nums), not i <= len(nums) -> Option AQuick Check:
Index out of range fixed by i < len(nums) [OK]
- Using <= instead of < in loops
- Misinitializing the map
- Incorrect frequency increment syntax
a and b, which Go code snippet correctly checks if b contains the same frequency of elements as a using the Frequency Counter Pattern?Solution
Step 1: Build frequency map for
Increment counts for each element inaa.Step 2: Decrement frequency map for
Decrement counts for each element inbb.Step 3: Check if all counts are zero
If any count is not zero, frequencies differ; otherwise, they match.Final Answer:
freq := make(map[int]int) for _, v := range a { freq[v]++ } for _, v := range b { freq[v]-- } for _, count := range freq { if count != 0 { fmt.Println(false) return } } fmt.Println(true) -> Option DQuick Check:
Increment a, decrement b, check zero counts [OK]
- Only checking presence, not frequency
- Using separate maps without comparing properly
- Assuming counts add up without balancing increments and decrements
Ready to prove it?
Pass the test and this pattern moves unknown
