Two Sum is the most famous warm-up in coding interviews. It teaches the single most useful trick in the whole field: trading memory for speed with a hash map.
Problem. Given an array of integers nums and an integer target, return the indices of the
two numbers that add up to target. Each input has exactly one answer, and you may not use the same
element twice.
Example: nums = [3, 2, 4], target = 6 → answer [1, 2] (because nums[1] + nums[2] = 2 + 4 = 6).
The slow way first
The obvious idea: try every pair. For each number, loop over all the others and check if they add up to the target. That works, but it is O(n²) — for a big array it is far too slow.
The question to ask: while I am looking at one number, what do I wish I already knew? I wish I knew whether its partner (the number that completes the target) has already shown up. A hash map lets me answer that in O(1).
The idea: remember what you've seen
Walk the array once. For each number num, its partner is need = target - num. Before storing num, check: have I already seen need? If yes, the pair is num and that earlier number — done. If no, remember num (store its value → index) and keep going.
The key insight: we check for the partner before adding the current number. That way we never pair a number with itself, and the first complete pair we find is the answer.
Walk through it
Step through the animation. The pointer i scans left to right. The seen map fills up underneath. When i reaches 4, its partner 2 is already in the map (we stored it a step earlier), so we stop and return both indices.
Pseudocode
make an empty map called "seen" # maps a value -> its index
for each index i with value num in nums:
need = target - num
if need is a key in seen:
return [seen[need], i] # found the pair
seen[num] = i # remember this number for later
return [] # (problem guarantees we never reach here)The Python solution
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
need = target - num
if need in seen:
return [seen[need], i]
seen[num] = i
return []seenis a dictionary mapping a value → the index where we saw it.enumerategives us both the indexiand the valuenumas we loop.need = target - numis the partner we are hoping to find.- Line 5 is the O(1) lookup — the heart of the trick.
need in seenchecks a hash map, not the whole array. - We store
seen[num] = iafter the check, so a number is never matched with itself.
Complexity
| Case | Time | Notes |
|---|---|---|
| Brute force (every pair) | O(n²) (slow) | two nested loops |
| Hash map (this solution) | O(n) (moderate) | one pass, O(1) lookups |
O(n) (moderate)We trade O(n) extra space (the map) for a big speed win: O(n²) → O(n). That trade — use a hash map to remember things and look them up instantly — shows up in a huge number of problems.
When this pattern shows up
Any time a problem asks "is there a pair / does this value exist / have I seen this before," reach for a hash map (set or dict). Two Sum, "contains duplicate," "valid anagram," and many others are all the same move: remember what you've seen so the next lookup is O(1).
Watch the ordering: check for the partner before inserting the current number. If you insert first,
a number could match itself (e.g. target = 6, num = 3 would "find" itself).
Practice
For nums = [3, 2, 4], target = 6, when i reaches the value 4, what is its partner and is it already in the map?
1. Why is the hash-map solution O(n) instead of O(n²)?
2. Why do we check for the partner before storing the current number?
3. What does the map store?
4. What is the extra space used by this solution?