3Sum
Given an integer array nums, return all unique triplets [a, b, c] drawn from three different positions such that a + b + c == 0. The result must not contain duplicate triplets (two triplets with the same three values, in any order, count as the same). The order of the triplets, and the order of values within each triplet, does not matter. Return the values themselves, not their indices. If no triplet sums to zero, return an empty list.
- 3 <= nums.length <= 3000
- -10⁵ <= nums[i] <= 10⁵
- The result must not contain duplicate triplets
nums = [-1,0,1,2,-1,-4][[-1,-1,2],[-1,0,1]]nums = [0,0,0][[0,0,0]]nums = [1,2,-2,-1][]We need every group of three numbers that adds up to zero, with no repeated triplet. The honest brute force is three nested loops over all triples — about N³/6 of them — checking each sum. At N = 3000 that is billions of checks. We can do much better, and the key is to notice we already know how to find two numbers with a target sum quickly.
Pick one number and call it the anchor. Once the anchor is fixed at value a, the rest of the job is: find two other numbers that add up to -a, so that all three together make zero. But "find a pair with a given target sum" is exactly Two Sum II — and we solved that with the converging two-pointer walk, as long as the array is sorted. So the plan writes itself: sort the array once, then let each position take a turn as the anchor, and for each anchor run the inward two-pointer search over the part of the array to its right.
nums.sort()
res = []
for i in range(len(nums) - 2):
if i > 0 and nums[i] == nums[i-1]:
continue # skip a repeated anchor (see below)
left, right = i + 1, len(nums) - 1
while left < right:
s = nums[i] + nums[left] + nums[right]
if s == 0:
res.append([nums[i], nums[left], nums[right]])
while left < right and nums[left] == nums[left+1]:
left += 1 # skip repeated left values
while left < right and nums[right] == nums[right-1]:
right -= 1 # skip repeated right values
left += 1
right -= 1
elif s < 0:
left += 1 # sum too small — grow it
else:
right -= 1 # sum too big — shrink it
return resThe inner while loop is Two Sum II unchanged: a too-small sum steps left up to a bigger number, a too-big sum steps right down to a smaller one, and the same safety argument carries over — because the sub-array is sorted, each move throws away a number that provably cannot complete this anchor's pair.
We sorted for the two-pointer walk, but it also hands us duplicate removal almost for free, because equal values now sit next to each other. There are two places a repeat can sneak in, and each has a one-line guard:
nums[i] == nums[i-1]) — reusing the same anchor value would only rediscover the exact same triplets. And right after recording a match, we slide left and right past any equal neighbors — otherwise the very next step would find the same pair of values again at a shifted position. Both guards work only because sorting put equal values side by side; on an unsorted array you would instead need a hash set of seen triplets, which costs extra memory and bookkeeping.The move here is worth keeping on its own: to find k numbers with a target sum, sort once, pin down k−2 of them with outer loops, and let the converging two-pointer walk handle the final pair. 3Sum is that recipe with k = 3 (one anchor); 4Sum is k = 4 (two nested anchors), and the idea keeps going. The cost is O(N²): N choices of anchor times an O(N) inner walk, and the one-time sort is only O(N log N), which disappears next to N². Whenever a problem says "find several numbers that add to a target" and warns about duplicates, reach for sort, then converge — the ordering pays for both the search and the de-duplication at once.
3Sum Strategy
Fix one, finding pair with Two Pointers
Key Insight
Sorting transforms the problem. By fixing one element nums[i], we reduce the problem to finding two numbers that sum to -nums[i], which is exactly Two Sum II.
Handling Duplicates
We skip duplicate values for both the pivot and the two pointers to ensure uniqueness of the triplets without using a Set.