When interviewers ask you to “find duplicates”, “pair elements”, or “group items by a property”, they are usually hinting at the hash‑map pattern. A hash map (often a Python dict) gives average O(1) insert and lookup, turning many naïve O(n²) solutions into linear time. The pattern is simple: walk the input once, store a key that represents the property you care about, and use the map to answer the question on the fly.
Why Hash Maps Matter
- Constant‑time access – In most languages the average cost of a
dictoperation is independent of the data size. - Space‑time trade‑off – You pay extra memory for speed; the trade‑off is usually worth it in interview constraints (n up to 10⁵ is common).
- Versatility – Counting frequencies, building adjacency lists, caching results, and deduplicating are all one‑liner with a map.
Signals That Call for a Hash Map
| Phrase in problem | Typical goal | How a map helps |
|---|---|---|
| "Find the first duplicate" | Detect repetition early | Store seen values, return when a key reappears |
| "Pair elements that sum to X" | Two‑sum style | Look up `X - current` in map |
| "Group by …" | Cluster similar items | Use the property as key, append to list of values |
| "Count occurrences" | Frequency analysis | Increment counter per key |
| "Longest streak of …" | Sliding‑window with history | Map index of last occurrence |
If the statement mentions “unique”, “frequency”, “pair”, or “group”, start thinking about a dictionary.
Worked Example: Longest Substring Without Repeating Characters
Problem: Given a string s, return the length of the longest substring that contains no duplicate characters.
Naïve approach
Iterate over every start index, expand until a repeat appears – O(n²).
Hash‑map solution
Maintain a map last_seen from character to its most recent index. Move a left pointer start only when a repeat is found.
def length_of_longest_substring(s: str) -> int:
last_seen = {}
start = 0
best = 0
for i, ch in enumerate(s):
# If ch was seen after start, slide start right after its previous index
if ch in last_seen and last_seen[ch] >= start:
start = last_seen[ch] + 1
last_seen[ch] = i
best = max(best, i - start + 1)
return best
Complexity – Each character is processed once; look‑ups and updates are O(1) average, so overall O(n) time and O(k) space where k is the size of the alphabet.
Pitfalls
- Forgetting to check
last_seen[ch] >= startleads to moving the start pointer backwards. - Using a list for
last_seenworks only when the key space is small and dense (e.g., ASCII); a dict is safer for Unicode. - Mutating the map while iterating over it is fine in Python because we only update existing keys, but adding or removing keys during iteration in other languages can cause concurrency issues.
Five Representative Practice Problems
Below are five problems that each highlight a different facet of the hash‑map pattern. The descriptions avoid copyrighted wording; you can find them on popular coding platforms.
1. Two‑Sum (Classic Pairing)
Goal: Return indices of two numbers that add up to a target.
Hint: While scanning, store target - nums[i] as the needed complement. If the current number is already a key, you have a pair.
2. Group Anagrams
Goal: Partition a list of strings into groups where each group contains anagrams. Hint: Use a sorted version of the string as the key. Append the original string to the list stored under that key.
3. Top K Frequent Elements
Goal: Return the k most frequent items from an array. Hint: First build a frequency map, then bucket by frequency (or use a min‑heap keyed by count). The map gives you O(n) counting before you pick the top k.
4. Longest Consecutive Sequence
Goal: Find the length of the longest run of consecutive integers in an unsorted array.
Hint: Insert all numbers into a set (hash‑map with dummy values). For each number that is the start of a sequence (num-1 not in set), walk forward counting until the next integer is missing.
5. Subarray Sum Equals K
Goal: Count subarrays whose sum equals a target value.
Hint: Keep a running prefix sum and a map from prefix value to its occurrence count. For each new prefix p, add map[p - k] to the answer, then increment map[p].
Common Mistakes and How to Avoid Them
- Assuming O(1) always – In worst‑case (many hash collisions) operations degrade to O(n). In practice, Python’s hash algorithm is robust, but be ready to discuss the theoretical bound.
- Mutable keys – Lists cannot be keys because they are mutable; use tuples or immutable representations.
- Over‑using space – Storing the entire input in a map when a sliding‑window solution suffices can blow memory limits. Explain why you chose the map and what the trade‑off is.
- Off‑by‑one errors – When using indices as values (e.g., Two‑Sum), remember whether you need to return 0‑based or 1‑based indices as the problem specifies.
When Not to Use a Hash Map
- The problem explicitly requires ordered output and the language’s map does not preserve insertion order (older Python versions). In that case, combine a map with a list or use
OrderedDict. - When the key space is tiny and dense (e.g., digits 0‑9), a simple array or bitmask may be faster and more memory‑efficient.
- If the input size is tiny (n < 20), the overhead of a map may not matter; a brute‑force solution can be clearer and acceptable.
How to Practice This
- Pick one of the five problems each day – Write the solution from scratch, then refactor to use a hash map if you initially used a different approach.
- Explain the solution aloud – Use Call Assistant to record yourself summarizing the map’s role; listening back helps solidify the pattern.
- Create variations – Change the constraint (e.g., require the answer in sorted order) and adapt your map‑based solution accordingly.
FAQ
Q: How do I know if a hash map will fit in memory? A: Estimate the number of distinct keys. If the problem caps n at 10⁵ and keys are simple scalars, a map usually fits comfortably. Mention the estimate if the interviewer asks.
Q: Can I use a hash map for floating‑point keys? A: It works, but beware of precision issues. Often it’s safer to round or convert to a string representation before using as a key.
Q: What if the language I’m using doesn’t have built‑in hash maps? A: Implement a simple hash table with open addressing or chaining, or explain the theoretical O(1) operations you’d expect from a standard library map.
Q: How do I handle duplicate keys when grouping items? A: Store a list (or another collection) as the map’s value and append each new item to that list. Initialize the list on first encounter.
Frequently asked questions
When should I prefer a hash map over sorting?
If the problem asks for counting, pairing, or grouping and you only need the result, a hash map gives linear time. Sorting adds O(n log n) overhead and is unnecessary unless ordered output is required.
What’s the worst‑case time complexity of a hash map operation?
In theory, a badly colliding hash function can degrade to O(n) per operation, but modern libraries use randomized hashing to keep collisions rare. Mention this edge case if the interviewer probes.
Can I use a hash map for range queries?
For static range queries, a map can store prefix sums, but dynamic range queries usually need a balanced tree or segment tree. Explain why a map alone isn’t sufficient for logarithmic updates.
How do I avoid mutating keys accidentally?
Choose immutable types (strings, numbers, tuples). If you need a composite key, build a tuple of the immutable components before inserting into the map.
#coding pattern#hash maps#interview prep#python#algorithm