Fix one number at a time and hunt for a pair that cancels it out: which turns three unknowns into a Two Sum II problem run once per fixed value.
Given an array, find every unique triplet that sums to zero. Checking every triple directly costs . Even before that, "every unique triplet" hides a second problem: the same values can be found more than once unless duplicates are handled deliberately.
Sorting first solves both problems at once. It makes the two-pointer sweep valid, and it puts equal values next to each other so they're cheap to skip.
Why fixing one value turns this into Two Sum II
Reduce to a problem you've already solved
- Fixing
nums[i]as the pivot turns "three numbers sum to zero" into "two numbers sum to-nums[i]", exactly Two Sum II, just with a target that moves as the outer loop advances. - The sorted order that makes the inner two-pointer sweep valid is the same proof as before: the sum tells you which side is hopeless to keep.
- Once
nums[i] > 0, no pivot from here on can reach zero with two non-negative-or-larger partners, so the outer loop can stop.
What sorting doesn't solve by itself
- Skipping duplicate values inside the inner sweep only avoids repeating a pair for one fixed pivot; you still need to separately skip a pivot value that repeats the previous one.
- It doesn't bound the output size: in the worst case (many zeros) the result itself has triplets, so the total work can't beat that no matter how the pointers move.
- Sorting discards the original indices (fine here, since the answer only needs values, not positions).
- "triplets" or "three numbers" that sum to a target
- "no duplicate triplets in the result"
- asked for every valid combination, not just one
- values (not original positions) matter in the answer
The pattern
- 1Sort the array.
- 2
For each index
i, skip it if it repeats the previous pivot. - 3
Two-pointer the remainder for target
-nums[i], skipping repeat values onleftandrightafter recording a hit. - 4Stop the outer loop once
nums[i] > 0.
Complexity
An O(n) two-pointer sweep runs once per pivot, dominating the O(n log n) sort.
Auxiliary space only, excludes the sort's internal use and the output list itself.
Common pitfalls
- 1
Forgetting to skip duplicate pivots
Not comparing
nums[i]tonums[i - 1]reruns the identical inner sweep for equal pivot values, producing the same triplet more than once. - 2
Forgetting to skip duplicates after a hit
Advancing
leftandrightby one without first skipping past equal neighbours re-records the same triplet on the next iteration. - 3
Starting the inner pointers at the wrong index
leftandrightmust start ati + 1andn - 1: startingleftat0lets the pivot pair with itself. - 4
Moving the wrong inner pointer
Same inversion risk as Two Sum II, just against a moving target: move
leftwhen the sum is too small,rightwhen it's too big.
Variants worth knowing
- 1
3Sum Closest: track the closest sum seen instead of matching exactly.
- 2
4Sum: fix two pivots instead of one, then two-pointer the rest; the same idea nested a level deeper.
- 3
Valid Triangle Number: fixes the largest value instead of walking forward, and counts a whole range of pairs per step instead of one at a time.

