Files
leetcode/docs/(algorithms)/01-frequency-map.mdx
T

119 lines
3.0 KiB
Plaintext

---
title: 'Frequency Map'
description: 'Converging/parallel index walk that prunes the O(n^2) pair space using order.'
---
## The idea
A frequency map is a hash table with one job: **count things**.
Key = the thing. Value = how many times you saw it.
One pass to build. O(1) to ask "how many?"
Most string and array problems fall to this question:
"Do these two collections contain the same stuff?"
Count both. Compare the counts.
## The picture
```mermaid
flowchart LR
S["'banana'"] --> C["Counter"]
C --> B["b → 1"]
C --> A["a → 3"]
C --> N["n → 2"]
style C fill:#1565c0,color:#fff
```
## The Python tool
`Counter` builds the map in one line. `defaultdict(int)` when you need to count by hand.
```python
from collections import Counter, defaultdict
count = Counter("banana") # {'a': 3, 'n': 2, 'b': 1}
count.most_common(2) # [('a', 3), ('n', 2)]
freq = defaultdict(int)
for c in "banana":
freq[c] += 1 # no KeyError, starts at 0
```
## Ransom Note (LC 383) — do I have enough letters?
Count the magazine. Spend letters as the note needs them.
Counter subtraction does this in two lines.
```python
from collections import Counter
def can_construct(ransom_note: str, magazine: str) -> bool:
need = Counter(ransom_note)
have = Counter(magazine)
return all(have[c] >= n for c, n in need.items())
```
## Top K Frequent (LC 347) — count, then rank
Two steps: count everything, then pick the k biggest counts.
```mermaid
flowchart LR
A["nums:<br/>1 1 1 2 2 3"] --> B["Count:<br/>1→3, 2→2, 3→1"]
B --> C["Buckets by count:<br/>slot 3: [1]<br/>slot 2: [2]<br/>slot 1: [3]"]
C --> D["Walk from top:<br/>[1, 2] ✓"]
style D fill:#2e7d32,color:#fff
```
Bucket sort trick: a number can appear at most n times.
So make n+1 buckets. Put each number in the bucket of its count.
Walk buckets from the top. O(n) — no sort, no heap.
```python
from collections import Counter
def top_k_frequent(nums: list[int], k: int) -> list[int]:
count = Counter(nums)
buckets = [[] for _ in range(len(nums) + 1)]
for num, freq in count.items():
buckets[freq].append(num)
result = []
for freq in range(len(buckets) - 1, 0, -1):
for num in buckets[freq]:
result.append(num)
if len(result) == k:
return result
```
## Say the trade-off out loud
Three ways to rank counts. Name them in the interview:
| Method | Time | When |
|---|---|---|
| Sort the counts | O(n log n) | Fine, simple |
| Heap of size k | O(n log k) | k small, streaming |
| Bucket sort | O(n) | Best — counts are bounded by n |
## Complexity
| | Time | Space |
|---|---|---|
| Build the map | O(n) | O(u) — unique items |
| Lookup | O(1) | — |
## Close-out ritual
Before you submit, say out loud:
1. Time and space complexity.
2. One edge case trace: empty string, k = number of unique items, or one element repeated n times.
## Plan problems
**A-set:** LC 217 · 242 · 1 · 49 · 347
**B-set:** LC 383 · 205 · 128 · 290