Example 1
ready- Input
nums = [ -1, 0, 1, 2, -1, -4 ]- Expected
[ [ -1, -1, 2 ], [ -1, 0, 1 ] ]- Why
- duplicate -1 values still produce each value triplet only once
A ledger can hold dozens of ways to pick three entries that cancel to zero. Your answer should describe the value combinations, not every set of positions that produced them.
Given an integer array nums, return every unique triplet of values whose sum is zero.
A few ground rules keep the output unambiguous:
nums.[a, b, c] with a <= b <= c.That sorted inner shape is the triplet's canonical form — one standard representation that makes value duplicates easy to recognize.
3 <= nums.length <= 3_000-100_000 <= nums[i] <= 100_000Hints
Three nested loops can inspect every i < j < k. If a sum is zero, sort those
three values before adding them to a set so repeated value triplets collapse.
Once nums is sorted, fix one value at index i. The other two values must add
to -nums[i], which turns the rest of the work into a two-pointer search.
Skip a fixed value when it matches the previous fixed value. After finding a triplet, move both pointers past every copy of the values they just used.
Can you reach O(n²) time without using a set to remove duplicate triplets afterward?
Visible cases
nums = [
-1,
0,
1,
2,
-1,
-4
][
[
-1,
-1,
2
],
[
-1,
0,
1
]
]nums = [
0,
0,
0,
0
][
[
0,
0,
0
]
]nums = [
1,
2,
-2,
-1
][]Interview signal
The honest first pass checks every choice of three positions. When a choice sums to zero, sort its three values into canonical form and place the tuple in a set. The set keeps ten index combinations of the same values from becoming ten answers.
def three_sum(nums: list[int]) -> list[list[int]]:
found: set[tuple[int, int, int]] = set()
n = len(nums)
for i in range(n - 2):
for j in range(i + 1, n - 1):
for k in range(j + 1, n):
if nums[i] + nums[j] + nums[k] == 0:
triplet = tuple(sorted((nums[i], nums[j], nums[k])))
found.add(triplet)
return [list(triplet) for triplet in found]If k is the number of unique triplets, Time O(n³) for the three loops.
Space O(k) for the deduplication set and returned triplets.
Sorting puts every value on a number line. Fix nums[i], then search the suffix with
left and right:
left rightward.right leftward.Skip nums[i] when it matches the previous fixed value. That prevents the same first
value from launching an identical search twice. Pointer-level skips handle duplicates
inside a successful triplet.
def three_sum(nums: list[int]) -> list[list[int]]:
nums.sort()
triplets: list[list[int]] = []
n = len(nums)
for i in range(n - 2):
if i > 0 and nums[i] == nums[i - 1]:
continue
if nums[i] > 0:
break
left, right = i + 1, n - 1
while left < right:
total = nums[i] + nums[left] + nums[right]
if total < 0:
left += 1
elif total > 0:
right -= 1
else:
triplets.append([nums[i], nums[left], nums[right]])
left_value = nums[left]
right_value = nums[right]
while left < right and nums[left] == left_value:
left += 1
while left < right and nums[right] == right_value:
right -= 1
return tripletsTime O(n²) — sorting costs O(n log n), then each fixed index gets one linear two-pointer scan. Space O(1) beyond the output when the array is sorted in place (the language's sorting routine may use internal workspace).
The useful shift is from “which three positions?” to “fix one value, then solve a sorted two-value search.” That's the same converging-pointer argument, nested one level deeper.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[
[
-1,
-1,
2
],
[
-1,
0,
1
]
]