Two Sum: Find a Pair in an Array That Sums to a Target
Two Sum is the most-asked coding interview problem ever. It’s LeetCode #1, the canonical opener at FAANG, AI labs, fintechs, and every hiring funnel that uses standard data-structures-and-algorithms questions. The problem itself is simple — find two indices in an array whose values sum to a target — but interviewers use it to evaluate fluency on time/space trade-offs, hash-map mechanics, and follow-ups that get progressively harder. This guide covers the standard approaches, working code, and the variations that interviewers ask after the basic solution lands.
Problem Statement
Given an array of integers nums and an integer target, return the indices of the two numbers that add up to target. Assume exactly one solution exists; you may not use the same element twice.
Examples:
nums = [2, 7, 11, 15],target = 9→[0, 1](2 + 7 = 9)nums = [3, 2, 4],target = 6→[1, 2](2 + 4 = 6)nums = [3, 3],target = 6→[0, 1]
Approach 1: Brute Force (O(n²))
Check every pair. Useful as the warm-up answer to demonstrate you understood the problem before optimizing.
def two_sum_brute(nums: list[int], target: int) -> list[int]:
"""O(n^2) time, O(1) space."""
n = len(nums)
for i in range(n):
for j in range(i + 1, n):
if nums[i] + nums[j] == target:
return [i, j]
return []
Complexity: O(n²) time, O(1) space. Acceptable for small inputs, rejected for any non-trivial array size.
Approach 2: Hash Map (Standard Answer, O(n))
For each element, the complement is target - element. If we’ve seen the complement already, return its index and the current index. Otherwise, store the current element with its index.
def two_sum(nums: list[int], target: int) -> list[int]:
"""O(n) time, O(n) space — single pass with hash map."""
seen = {} # value -> index
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
# Tests
print(two_sum([2, 7, 11, 15], 9)) # [0, 1]
print(two_sum([3, 2, 4], 6)) # [1, 2]
print(two_sum([3, 3], 6)) # [0, 1]
Complexity: O(n) time average (hash map lookups are O(1) amortized), O(n) space.
This is the answer the interviewer expects. Single pass, clean indexing, handles duplicates correctly because we check seen before adding the current element.
Approach 3: Two Pointers (For Sorted Input)
If the array is already sorted, two pointers from both ends gives O(n) time and O(1) space. The trick is the array must be sorted (or you must accept O(n log n) sorting cost).
def two_sum_sorted(sorted_nums: list[int], target: int) -> list[int]:
"""O(n) time, O(1) space — assumes sorted input."""
left, right = 0, len(sorted_nums) - 1
while left < right:
s = sorted_nums[left] + sorted_nums[right]
if s == target:
return [left, right]
elif s < target:
left += 1
else:
right -= 1
return []
Complexity: O(n) time, O(1) space (vs O(n) for the hash map approach). The catch: you need a sorted array. If the original problem requires returning indices into the unsorted array, you must track original indices through the sort, which complicates the code.
This is LeetCode #167 (Two Sum II — Input Array is Sorted). Different problem; same name family.
Common Variations
Two Sum — return all pairs
What if there are multiple valid pairs and you must return them all? Switch from “return on first match” to “collect all matches.” Be careful about duplicates: [1, 1, 2] with target 3 — does [0, 2] and [1, 2] count as two pairs or one? Clarify with the interviewer.
3Sum (LeetCode #15)
Find all triplets that sum to zero. Standard approach: sort the array, then for each element, use two pointers on the remaining elements to find pairs summing to its negation. O(n²) time, O(1) space (excluding sorting).
def three_sum(nums: list[int]) -> list[list[int]]:
"""O(n^2) time."""
nums.sort()
result = []
n = len(nums)
for i in range(n - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue # skip duplicate first element
left, right = i + 1, n - 1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s == 0:
result.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
left += 1
right -= 1
elif s < 0:
left += 1
else:
right -= 1
return result
4Sum and beyond
Generalize 3Sum recursively. K-sum is O(n^(k-1)) with the standard approach — the time grows exponentially in k.
Two Sum on a stream / data structure design
(LeetCode #170) Implement TwoSum as a class with add(num) and find(value) operations. Trade-off: optimize add or optimize find. Most candidates implement add as O(1) (insert into a hash map of counts) and find as O(n) (iterate and check complements).
class TwoSum:
def __init__(self):
self.counts = {}
def add(self, num: int) -> None:
self.counts[num] = self.counts.get(num, 0) + 1
def find(self, value: int) -> bool:
for num, count in self.counts.items():
complement = value - num
if complement == num and count > 1:
return True
if complement != num and complement in self.counts:
return True
return False
Common Mistakes
- Storing the value in the hash before checking for the complement. If you store first and check second,
nums = [3, 3], target = 6matches the first 3 against itself. Always checkcomplement in seenbeforeseen[num] = i. - Using a set instead of a dict. Sets don’t preserve indices. The problem asks for indices, not values; you need a dict from value to index.
- Mishandling duplicates in the brute-force version. The inner loop must start at
i + 1, noti, to avoid pairing an element with itself. - Sorting and forgetting original indices. If the problem requires indices into the unsorted array, sorting destroys the information unless you track it. Pair each element with its original index, sort by value, and return paired indices.
- Not handling the no-solution case. The problem statement may guarantee a solution exists; in real code, return an empty array or raise an exception when nothing matches.
Frequently Asked Questions
What’s the expected interview answer?
Hash map, single pass, O(n) time and O(n) space. State the brute force as a warm-up if you have time, but don’t dwell on it. Write the hash-map solution cleanly with the “check before insert” ordering. The interview is testing fluency, not creativity; a confident, correct hash-map solution in under 5 minutes is the goal.
Why is “check before insert” the correct ordering?
Otherwise the same element can match itself. Consider nums = [3, 3], target = 6. If you insert 3 at index 0 first and then check for complement (which is also 3), you find it in the dict at index 0 — which is the current element, not a different one. Checking first ensures seen contains only previously-seen elements.
Can Two Sum be solved in O(n) time and O(1) space?
Not for the general unsorted case. The hash-map approach takes O(n) space; sorting then two-pointer takes O(n log n) time. There’s a fundamental trade-off: either you preprocess (sort) or you remember (hash). For the version where the array is sorted, two-pointer gives O(n) time + O(1) space. For unsorted with O(1) space, you’re stuck at O(n²) — there’s no known better.
What’s the typical follow-up after Two Sum?
3Sum (LeetCode #15) is the most common — same family of problems but harder. Sometimes Two Sum II (sorted input, two-pointer answer expected) or the streaming version (LeetCode #170, design problem). Strong candidates anticipate the follow-up; if you finish Two Sum quickly, mention how to extend to 3Sum to signal you’re ready for it.
How does Two Sum show up in real engineering work?
Almost never directly. The lesson interviewers care about — recognizing when a hash map turns O(n²) into O(n) — applies constantly to real work. Lookup tables, deduplication, set-membership tests are the practical face of this pattern. The problem itself is a vehicle for that intuition.
See also: Missing or Duplicate Number in an Array • Right Rotate an Array by K Elements • Longest Palindromic Substring
💡Strategies for Solving This Problem
The Hash Map Classic
This is "Two Sum" - one of the most common interview questions ever. I've seen it at Google, Facebook, and Amazon. Everyone should know this cold.
The Problem
Given an array of numbers and a target sum, find two numbers that add up to the target. Return their indices.
Example: nums = [2, 7, 11, 15], target = 9
Answer: [0, 1] because nums[0] + nums[1] = 2 + 7 = 9
Naive Approach: Nested Loops
Try every pair: O(n²) time, O(1) space. Too slow.
Better: Hash Map
The key insight: When we see number x, we need to find (target - x).
Use a hash map to remember what we've seen:
- For each number, check if (target - number) is in the map
- If yes, we found the pair
- If no, add current number to map
O(n) time, O(n) space. Single pass.
Why Hash Map Wins
Hash map lookup is O(1). So checking "have we seen target - x?" is instant.
Without it, we'd need to search the array each time - that's O(n), making total O(n²).
Variation: Sorted Array
If array is sorted, you can use two pointers (left and right). Move them based on whether sum is too small or too large. O(n) time, O(1) space.
But if array isn't sorted, sorting first takes O(n log n), which is worse than hash map.
At Google
They asked me this as a warmup. Then asked: "What if there are multiple pairs?" Return all pairs or just one? "What if no solution exists?" Return empty array or null?
These clarifications matter. Always ask before coding.