Two Sum
Find the two numbers in an array that add up to a target, using a hash map for O(n) lookups
Problem Statement
Given an array of integers nums and an integer target, return the indices of the two numbers that add up to target.
You may assume each input has exactly one solution, and you may not use the same element twice. You can return the answer in any order.
Input: nums = [2, 7, 11, 15], target = 9
Output: [0, 1]
Why: nums[0] + nums[1] = 2 + 7 = 9
Input: nums = [3, 2, 4], target = 6
Output: [1, 2]Intuition
Start with the obvious idea: try every pair. Take 2, check it against 7, 11, 15. Take 7, check it against 11, 15. That works, but for an array of 10,000 numbers it means about 50 million comparisons.
Here is the shift in thinking that makes it fast:
The key insight
You are never really searching for "some pair that works". While standing on the number 2 with target = 9, you are searching for exactly one specific number: 9 - 2 = 7. That number has a name — the complement.
So the question changes from "which of the remaining numbers pairs with me?" (slow, requires scanning) to "have I already seen the number 7?" (fast, if you kept notes).
A hash map is the notebook. Writing down number → index costs O(1), and asking "is 7 in my notes?" also costs O(1).
Real-world analogy
Imagine you are matching socks from a laundry pile. The slow way is to pick one sock and compare it against every other sock. The fast way: lay each sock on a table in a labelled spot as you pull it out. When you pull out a red sock, you don't search — you look straight at the "red" spot to see if its partner is already there.
Approach
Create an empty hash map
It will store {number: index} for every number you have already walked past.
Walk the array once, keeping the index
For each num at position i, compute complement = target - num.
Check the map before inserting
If complement is already a key in the map, you have found the pair — return [map[complement], i].
Checking before inserting is what stops you from using the same element twice. If target = 6 and num = 3, you don't want to match 3 with itself.
Otherwise, record the current number
Store map[num] = i and continue to the next element.
Watch it run
empty
Solution
def two_sum(nums: list[int], target: int) -> list[int]:
"""Return the indices of the two numbers that add up to target."""
seen: dict[int, int] = {} # number -> index it was found at
for i, num in enumerate(nums):
complement = target - num
# Check before inserting so an element can't pair with itself.
if complement in seen:
return [seen[complement], i]
seen[num] = i
return [] # unreachable when a solution is guaranteedWhy `match !== undefined` and not `if (match)`
In TypeScript, an index of 0 is falsy. If the answer lives at index 0, if (match) silently skips it. Always compare against undefined when a Map can legitimately hold 0.
Complexity Analysis
Time Complexity
O(n)
Space Complexity
O(n)
- Time — one pass over
nelements, and each hash-map read or write is O(1) on average. Compare with the brute-forceO(n²): atn = 10,000that is 10,000 steps instead of ~50,000,000. - Space — in the worst case (the pair is the last two elements) the map holds nearly every number.
Edge Cases
Related Problems
- Contains Duplicate — the same "have I seen this before?" trick, with a set instead of a map
- Group Anagrams — a hash map keyed by a computed signature
- Container With Most Water — when the array is sorted-ish, two pointers beat a map