3Sum – Solution & Complexity
Solution Walkthrough
1. Understanding the Problem
- You need every unique triplet of values in
numsthat sums to zero. - "Unique" means by value, not by index — if the same three numbers can be picked in more than one way, only report them once.
- A brute-force triple nested loop checking every
(i, j, k)combination works but isO(n^3)and still needs a set to dedupe.
2. Reducing to Two Sum via Sorting
- Sort
numsfirst. Sorting does two things: it makes duplicate values adjacent (easy to skip), and it lets you solve the remaining two-value subproblem with two pointers instead of a nested loop. - Fix the first value
nums[i]in a single pass. For eachi, you now need two other numbers,landrwithl, r > i, such thatnums[l] + nums[r] == -nums[i]. That's exactly the sorted-array two-pointer pattern from Two Sum II. - Skip repeated values of
nums[i](if i > 0 and nums[i] == nums[i-1]: continue) so the same first value isn't used to start two identical triplets.
3. Two-Pointer Scan for the Remaining Pair
- For each
i, startl = i + 1andr = n - 1. - If
nums[i] + nums[l] + nums[r] < 0, the sum is too small — movelright to increase it. - If it's
> 0, the sum is too big — moverleft to decrease it. - If it's exactly
0, record[nums[i], nums[l], nums[r]], then advance both pointers inward, skipping over any further duplicate values at the newl/rso the same pair isn't recorded twice.
4. Final Solution (all languages)
Sorting is O(n log n), and the fixed-index + two-pointer scan is O(n) per index, giving O(n^2) total — the standard optimal complexity for 3Sum.
5. Common mistakes & interviewer follow-ups
- Forgetting to sort first — the two-pointer shrink/grow logic only works because the remaining subarray is ordered.
- Skipping the duplicate-value check on
ibut forgetting it onl/rtoo (or vice versa) — both are needed to avoid duplicate triplets. - Advancing
landrinside the duplicate-skippingwhileloops without also checkingl < r, which can walk past the valid window. - Follow-ups: how would you solve 4Sum with the same pattern (fix two indices, two-pointer the rest)? What changes if the array can't be sorted (e.g. you must preserve original indices)?