Overview
A hash map stores key-value pairs and supports insert, lookup, and delete in O(1) on average. A hash function converts the key into an integer, which picks a bucket in an internal array. Collisions (two keys in one bucket) are handled by chaining or probing.
Hash maps are the most common tool for turning an O(n^2) solution into O(n). Whenever you catch yourself searching for something you saw earlier, ask: can I remember it in a map?
The attendant turns your ticket number into a hook position instantly and walks straight to it. If two coats share a hook, they hang one behind the other and the attendant checks the few coats there. Lookup does not depend on how many coats are in the room.
When to use it
- You need to remember something about earlier elements: indexes, counts, prefix sums.
- Counting frequencies of characters, words, or numbers.
- Grouping items by a computed key (anagrams, same pattern).
- Caching / memoization of computed results.
- Building an index from an ID to an object.
Problem patterns it solves
Recognize it when: find two elements that combine to a target.
- 1. Two Sum
- 454. 4Sum II
- 2215. Find the Difference of Two Arrays
- 350. Intersection of Two Arrays II
Recognize it when: most frequent, first unique, majority, equalize frequencies.
- 387. First Unique Character in a String
- 347. Top K Frequent Elements
- 2423. Remove Letter To Equalize Frequency
- 1207. Unique Number of Occurrences
Recognize it when: anagrams, isomorphic strings, same shape.
- 49. Group Anagrams
- 205. Isomorphic Strings
- 290. Word Pattern
Recognize it when: count subarrays with sum k or divisible by k.
- 560. Subarray Sum Equals K
- 1248. Count Number of Nice Subarrays
- 974. Subarray Sums Divisible by K
- 525. Contiguous Array
Recognize it when: last seen position, nearby duplicates, longest span.
- 219. Contains Duplicate II
- 3. Longest Substring Without Repeating Characters
- 128. Longest Consecutive Sequence
Recognize it when: O(1) operations on custom structures.
- 146. LRU Cache
- 380. Insert Delete GetRandom O(1)
- 706. Design HashMap
Where it is used in real software
Redis and Memcached are distributed hash maps from key to value; application caches are in-memory maps.
Hash joins build a map from join key to rows of the smaller table, then probe it with each row of the larger table.
JavaScript objects, Python dicts, and symbol tables in compilers are hash maps; V8 falls back to dictionary mode for objects with many dynamic keys.
Content-addressed storage (Git objects, Docker layers) looks up data by its hash to avoid storing duplicates.
Key terms
- Hash function
- Maps a key to an integer. Must be deterministic; good ones spread keys uniformly.
- Bucket
- Slot in the internal array chosen by hash(key) mod capacity.
- Collision
- Two different keys map to the same bucket.
- Load factor
- entries / buckets. When it passes a threshold (0.75 in Java), the table resizes.
- Rehashing
- Allocating a larger array and reinserting every entry; amortized O(1) per insert.
What happens on put(key, value)
- 1Hash the key
Compute key.hashCode() (Java) or the engine's internal hash.
- 2Pick the bucket
index = hash mod capacity (Java uses hash & (capacity - 1) with a power-of-two capacity).
- 3Search the bucket
Compare keys with equals. If found, replace the value.
- 4Insert
Otherwise add a new entry to the bucket's chain.
- 5Resize if needed
If the load factor is exceeded, double the capacity and redistribute all entries.
Two Sum with a hash map
nums = [2, 7, 11, 15], target = 9
| i | nums[i] | Need (target - nums[i]) | Seen map before | Action |
|---|---|---|---|---|
| 0 | 2 | 7 | {} | 7 not seen, store 2 -> 0 |
| 1 | 7 | 2 | {2: 0} | 2 seen at index 0, return [0, 1] |
NOWi: 0 | nums[i]: 2 | Need (target - nums[i]): 7 | Seen map before: {} | Action: 7 not seen, store 2 -> 0
The map remembers every value already passed, so each element needs one O(1) lookup: O(n) total instead of checking all pairs in O(n^2).
Implementation
// Use Map, not {}: any key type, reliable size, no prototype keysfunction twoSum(nums, target) { const seen = new Map(); for (let i = 0; i < nums.length; i++) { const need = target - nums[i]; if (seen.has(need)) return [seen.get(need), i]; seen.set(nums[i], i); } return [];} function groupAnagrams(words) { const groups = new Map(); for (const word of words) { const counts = new Array(26).fill(0); for (const ch of word) counts[ch.charCodeAt(0) - 97]++; const key = counts.join("#"); // O(k) key instead of sorting O(k log k) if (!groups.has(key)) groups.set(key, []); groups.get(key).push(word); } return [...groups.values()];} // 1248. Count Number of Nice Subarrays (exactly k odd numbers)function numberOfSubarrays(nums, k) { const countByOdds = new Map([[0, 1]]); let odds = 0, result = 0; for (const x of nums) { if (x % 2 === 1) odds++; result += countByOdds.get(odds - k) ?? 0; countByOdds.set(odds, (countByOdds.get(odds) ?? 0) + 1); } return result;} function longestConsecutive(nums) { const set = new Set(nums); let best = 0; for (const x of set) { if (set.has(x - 1)) continue; // only start at the beginning of a run let length = 1; while (set.has(x + length)) length++; best = Math.max(best, length); } return best;}Complexity and performance
With a good hash function and resizing.
All keys collide; Java 8+ trees large buckets, giving O(log n).
Visits every bucket.
Plus unused bucket capacity.
Trade-offs
HashMap is O(1) but unordered. TreeMap (red-black tree) is O(log n) but supports floor, ceiling, and ordered iteration.
If keys are small integers or letters, an array index is faster and uses less memory.
Each entry stores the key, value, hash, and a next pointer; Java boxing of int keys adds more.
Variants and related techniques
Each bucket holds a list of entries (Java HashMap).
Collisions probe other slots in the same array (Python dict, many C++ maps).
Preserves insertion or access order; JS Map also iterates in insertion order.
A map from item to count; Java uses map.merge(key, 1, Integer::sum).
Common mistakes
- Using a JS object {} as a map with arbitrary keys.
Fix: Object keys become strings and inherit prototype properties like 'constructor'. Use Map.
- Mutable objects as keys.
Fix: If a key's hash changes after insertion, it can never be found again. Use immutable keys.
- Overriding equals without hashCode in Java.
Fix: Equal objects must have equal hash codes, or lookups fail.
- Comparing Integer values with == in Java.
Fix: Boxed Integers above 127 are different objects; use .equals or unbox.
Interview questions
Why is a hash map O(1) on average but O(n) worst case?
A good hash spreads keys evenly, so each bucket holds a constant number of entries. If many keys collide into one bucket, a lookup must scan them all.
What happens when a hash map resizes?
It allocates a larger bucket array (usually double) and reinserts every entry. That single operation is O(n), but it happens rarely enough that insert stays amortized O(1).
How do you design a hash map from scratch?
An array of buckets, a hash function mapping keys to indexes, chaining or probing for collisions, and resizing when the load factor exceeds a threshold.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| 1. Two Sum | Easy | Complement lookup. |
| 350. Intersection of Two Arrays II | Easy | Frequency counts. |
| 49. Group Anagrams | Medium | Canonical keys. |
| 560. Subarray Sum Equals K | Medium | Prefix sums in a map. |
| 1248. Count Number of Nice Subarrays | Medium | Prefix count of odds. |
| 128. Longest Consecutive Sequence | Medium | Start only at run beginnings. |
| 706. Design HashMap | Easy | Buckets and chaining. |