Learn DSA · Lesson 4 of 9

Hash Maps

Trade memory for time by remembering what you have already seen.

The idea

A hash map answers one question in constant time: have I seen this before, and what was it attached to?

That sounds modest. It is the single most common way an O(n²) solution becomes O(n).

The pattern is almost always the same shape. You are looping over data and, for each element, asking a question about the elements you have already passed. The naive version answers that by looping again — comparing every element against every other. The hash-map version answers it by having written those elements down as it went.

for each element:
    if the map already answers my question -> done
    otherwise, record this element and move on

The cost is memory: you are storing up to n entries to avoid the second loop. That trade is the whole idea, and it is why "time complexity" and "space complexity" are usually discussed together.

Walkthrough

One pass over the array, building a count for each value. Watch how every element is read exactly once.

What it costs

time
O(1) average per lookup or insert
space
O(n) for n stored entries

Average, not worst. A pathological set of keys that all collide degrades lookups to O(n) — rare in practice, and the reason hash functions matter.

When to reach for it

Rather than the obvious alternative

Sorting first

Sorting costs O(n log n) and buys you order. If you only need counts or membership, hashing does it in O(n) and order was never the point.

A nested loop

The direct trade this structure exists for: O(n²) becomes O(n) by remembering instead of re-searching.

A tree map

Choose the tree when you need keys in sorted order, range queries, or a predecessor. A hash map gives you none of those, and is faster when you do not need them.

How to spot it

Where it goes wrong

Recording before you look

If you add the current element to the map before checking for its match, an element can pair with itself. Check first, then record.

Storing the value when you need the index

Most problems want *where* something was, not what it was. Map the value to its index, not to true.

Assuming keys are unique

Duplicate values overwrite each other. If earlier occurrences matter, store a list of indices rather than one.

Try it

Two short checks. They run the same way the practice problems do — write the function, press Run.

Return true if any value appears twice in nums, otherwise false. One pass, using a set.

Or press ⌘↩

Tests

4 cases, 1 hidden
calltypeexpectedresult
hasDuplicate([1,2,3,2])a repeattrue
hasDuplicate([1,2,3])all distinctfalse
hasDuplicate([])emptyfalse
withheldhiddenwithheld

Hidden cases run too — their inputs aren't listed here, so aim for a general solution rather than one fitted to the cases above.

Hints

Stuck? Hints open one at a time, each giving a little more away.

2 hints left

Return an object mapping each value in nums to how many times it appears.

Or press ⌘↩

Tests

3 cases, 1 hidden
calltypeexpectedresult
countValues([1,2,2,3])mixed{"1":1,"2":2,"3":1}
countValues([])empty{}
withheldhiddenwithheld

Hidden cases run too — their inputs aren't listed here, so aim for a general solution rather than one fitted to the cases above.

Hints

Stuck? Hints open one at a time, each giving a little more away.

2 hints left

Practise it

Build it

The problems above are one function each. These assemble the same ideas into a working thing across several files.