◐ ai-teacher

🧩 Data Structures & Algorithms · Chapter 3

Hashing and hash maps

A list makes you ask every item 'are you the one?'. A hash map computes where the answer lives and goes straight there — which is why it turns so many O(n²) solutions into O(n).

Study this lesson free in the app →

The basics

A hash map (Python dict, Java HashMap, JavaScript Map) stores key → value pairs and finds any key in about the same time no matter how many it holds. A hash set (set) is the same thing with keys only.

The problem it solves: checking "have I seen this?" or "what's stored under this name?" in a list means scanning — O(n). A hash map instead runs the key through a hash function that turns it into a number, and uses that number to pick a bucket directly: bucket = hash(key) % number_of_buckets. No scanning, so lookups, inserts and deletes are O(1) on average.

The mental model: a cloakroom. You hand in your coat and get ticket 47; to collect it, the attendant walks straight to hook 47. Nobody searches the racks.

Words you must know 5

Hash function
turns a key into an integer; the same key must always give the same number.
Bucket
one slot of the underlying array.
Collision
two different keys landing in the same bucket. Unavoidable; handled by chaining (a small list per bucket) or open addressing (probe for the next free slot).
Load factor
entries ÷ buckets. When it gets too high the table resizes (allocates more buckets and re-places every key).
Complexity
average O(1) per operation, worst case O(n) if everything collides; O(n) space.

Explained

Find two prices in a list of 100,000 that add up to exactly your gift-card balance.

Compare every pair: about 5 billion checks.

Walk the list once and, for each price, ask a hash set "have I already seen the price that would complete this?": 100,000 checks.

Same answer. The hash map is the difference between minutes and milliseconds.

The cloakroom

A theatre cloakroom has 100 hooks. When you hand in your coat, the attendant looks at your surname, does a quick calculation, and hangs it on hook 47. When you come back, the same calculation sends them straight to hook 47.

That calculation is the hash function. The hooks are buckets.

Sometimes two guests compute to the same hook. The attendant just hangs the second coat on top — a collision, handled by chaining. Finding your coat now means checking two coats on one hook, not walking all 100.

On a sold-out night, hooks hold five coats each and service slows. So the theatre installs a second rack and re-hangs every coat by the new calculation — a resize. Painful once, then fast again.

Precisely

Insert key → value:

  1. Compute h = hash(key) — any integer, possibly huge.
  2. Choose a bucket: i = h % capacity.
  3. If the bucket is empty, store the pair. If not, a collision:

- Chaining (Java's HashMap): append to that bucket's list. - Open addressing (Python's dict): probe other slots in a fixed sequence until a free one turns up.

  1. If entries ÷ capacity passes a threshold (about 2/3 in CPython, 0.75 in Java), resize: allocate a larger array and re-insert everything, because h % capacity changes when capacity does.

Lookup repeats steps 1–2, then compares keys in that bucket with == until it finds a match.

| Operation | Average | Worst | | --- | --- | --- | | insert / lookup / delete | O(1) | O(n) | | iterate all entries | O(n) | O(n) | | space | O(n) | O(n) |

The worst case needs many keys in one bucket. A decent hash function plus resizing makes that vanishingly rare on ordinary data.

Plenty of buckets: every key on its own hook

Five keys, ten buckets — a load factor of 0.5. Watch each key turn into a bucket number. With this much room, keys rarely share a bucket, so a lookup is one hash and one comparison: O(1).

Too few buckets: collisions pile up

Seven keys, three buckets — a load factor of about 2.3. At least one bucket must hold three or more keys, and chains form. Finding a key at the end of a long chain means walking it item by item — a little linear search. This is why real tables resize long before they look like this.

The three patterns you'll use weekly

from collections import Counter, defaultdict

# 1. Count frequencies — O(n) time, O(k) space for k distinct items
Counter("mississippi").most_common(2)     # [('i', 4), ('s', 4)]

# 2. Seen-before / dedupe — O(n) time, O(n) space
def first_repeat(items):
    seen = set()
    for x in items:
        if x in seen:
            return x
        seen.add(x)
    return None

# 3. Group by a computed key — O(n · k log k) for n words of length k
def group_anagrams(words):
    groups = defaultdict(list)
    for w in words:
        groups["".join(sorted(w))].append(w)    # 'tea' -> 'aet'
    return list(groups.values())

group_anagrams(["eat", "tea", "tan", "ate", "nat", "bat"])
# [['eat', 'tea', 'ate'], ['tan', 'nat'], ['bat']]

Keys must be hashable: use a tuple (row, col), never a list [row, col].

When hashing gets expensive

Gotchas

Words to know

Hash functionA function that maps a key to an integer; the same key must always produce the same value.
BucketOne slot of the hash table's underlying array, chosen by hash(key) % capacity.
CollisionTwo different keys mapping to the same bucket.
ChainingCollision handling where each bucket holds a small list of all keys that landed there.
Open addressingCollision handling where a colliding key probes other slots until it finds a free one (used by Python's dict).
Load factorEntries divided by buckets; when it passes a threshold the table resizes.
HashableHas a hash value that never changes during its lifetime — required for dict keys and set members.

In two minutes

Test yourself

1. What is the average time complexity of looking up a key in a Python dict?

  1. O(1)
  2. O(log n)
  3. O(n)
  4. O(n log n)
Show the answer

O(1) — The key's hash points straight at a bucket, so the work doesn't depend on how many entries exist. O(log n) is a balanced tree; O(n) is the rare worst case when everything collides.

2. What is a collision in a hash table?

  1. Two identical keys inserted twice
  2. Two different keys mapping to the same bucket
  3. The table running out of memory
  4. A key whose hash is negative
Show the answer

Two different keys mapping to the same bucket — Different keys, same bucket. Inserting the same key twice simply overwrites the value — that's not a collision.

3. A hash table has 8 buckets and 6 entries. What is its load factor?

  1. 8
  2. 1.33
  3. 0.75
  4. 48
Show the answer

0.75 — Load factor = entries ÷ buckets = 6 ÷ 8 = 0.75. That's exactly Java's default resize threshold.

4. You need to count how often each word appears in a 1 GB text file. Best tool?

  1. A sorted list, searched with binary search for each word
  2. A list of (word, count) pairs, scanned for each word
  3. A nested loop comparing each word with every other
  4. A dict (or Counter) from word to count
Show the answer

A dict (or Counter) from word to count — One pass with O(1) average updates: O(n) total. Scanning a list per word is O(n × distinct words); keeping a sorted list costs O(n) shifting per new word.

5. You want to store grid positions like (row, col) in a set. What should each position be?

  1. A list [row, col]
  2. A tuple (row, col)
  3. A dict {'row': r, 'col': c}
  4. Any of these
Show the answer

A tuple (row, col) — Set members must be hashable and unchanging. Tuples of numbers are; lists and dicts are mutable and raise TypeError: unhashable type.

6. Two-sum with a dict: walk the array once, checking target - x in seen before inserting x. Complexity?

  1. O(n) time, O(n) space
  2. O(n²) time, O(1) space
  3. O(n log n) time, O(1) space
  4. O(n) time, O(1) space
Show the answer

O(n) time, O(n) space — n iterations × O(1) average per check = O(n) time, and the dict can hold up to n values. O(n log n)/O(1) is the sort + two-pointers alternative.

There are 9 questions, 4 puzzles and 6 recall cards for this lesson in the app — the recall cards come back on later days, just before you would forget.

Learn it so it stays. Read it, test yourself, then recall it on two different days. The app schedules that for you, free.

Start this lesson →