We need to find all unique triplets (three elements) in the array that add up to zero. Two requirements make this harder than Two Sum.
First, we need all valid triplets, not just one. Second, we need to avoid duplicate triplets in our result. For example, if the array has two -1s, both [-1, 0, 1] using the first -1 and [-1, 0, 1] using the second -1 count as the same triplet. We only want it once.
Fixing one element nums[i] reduces the rest of the problem to a familiar one: the other two elements must sum to -nums[i], which is Two Sum. So 3Sum amounts to running a Two Sum search once per element.
3 <= nums.length <= 3000 → With n up to 3000, O(n^2) gives us about 9 million operations, which is fine. O(n^3) gives 27 billion, which is too slow.-10^5 <= nums[i] <= 10^5 → Values fit in a standard integer. No overflow concerns for sums of three elements.Check every combination of three indices (i, j, k) with i < j < k and test whether nums[i] + nums[j] + nums[k] == 0. Each match is a candidate triplet.
Duplicates still need handling, because the same three values can come from different index combinations. Sorting each found triplet before inserting it into a set normalizes the order: [-1, 0, 1] and [0, -1, 1] both become [-1, 0, 1], and the set keeps one copy.
(i, j, k) where i < j < k.nums[i] + nums[j] + nums[k] == 0.At n = 3000, the triple loop performs about 27 billion operations, well past any time limit. The next approach applies the reduction from the problem analysis: fix one element and solve the remaining pair search as Two Sum with a hash set.
Fixing nums[i] turns the remaining search into Two Sum: find two elements after index i that sum to -nums[i]. With a hash set, each such search takes O(n). For each j past i, compute complement = -nums[i] - nums[j]; if the complement is among the values already scanned, the pair (complement, nums[j]) completes a triplet.
Duplicate handling relies on sorting the array first. Sorting puts equal values next to each other, which makes them cheap to skip: the outer loop skips repeated values of nums[i], and after recording a triplet the inner loop advances j past every remaining copy of nums[j].
This skipping catches every duplicate. For a fixed nums[i], take a valid pair of values (a, b) with a <= b. While j sits on an occurrence of a, the needed complement is b, which is at least as large and therefore has not appeared yet in the sorted scan. The pair is first recorded when j reaches an occurrence of b with a already in the set. All copies of b form one consecutive run, and the skip loop moves j past that entire run, so the same pair cannot be recorded a second time.
i from 0 to n-3:nums[i] is the same as nums[i-1] (avoid duplicate first elements).target = -nums[i].nums[i+1...n-1] that sum to target.nums[j], compute complement = target - nums[j].[nums[i], complement, nums[j]] (already in sorted order, since the complement appeared earlier in the scan), then skip duplicates for j.nums[j] to the set.This reaches O(n^2) time, but each outer iteration builds a hash set of up to n elements. The array is already sorted for duplicate handling, and sorted order supports a pair search that needs no extra memory at all: two pointers moving toward each other.
The array is sorted anyway for duplicate handling, and after fixing nums[i], the goal is two elements in the remaining sorted subarray that sum to -nums[i]. In sorted data, a pair with a given sum can be found with two pointers and no extra memory.
Place one pointer left at the start of the remaining subarray (i+1) and another pointer right at the end. If the sum of the three elements is too small, move left right to increase it. If it's too large, move right left to decrease it. If it's exactly zero, we found a triplet.
Each pointer moves in only one direction, so the inner search is O(n). Combined with the outer loop, the total is O(n^2) with O(1) extra space.
Why is it safe to discard an element on every move? When the sum is negative, nums[left] cannot form a zero triplet with anything still in range: nums[right] is the largest remaining candidate, and even it was not enough. So left can advance without losing a solution. Symmetrically, when the sum is positive, nums[right] is too large to pair with anything still in range, since nums[left] is the smallest remaining candidate. Every move permanently eliminates one element that provably belongs to no unreported triplet, which is why no pair is missed and the inner loop ends after at most n moves.
Duplicate skipping relies on sorting placing equal values next to each other. After recording a triplet, the inner loops move left past every copy of nums[left] and right past every copy of nums[right], and the outer loop skips repeated values of nums[i], so each triplet enters the result once.
i from 0 to n-3:nums[i] > 0, break (since the array is sorted, no three positive numbers can sum to zero).nums[i] equals nums[i-1] (avoid duplicate first elements).left = i + 1 and right = n - 1.left < right:sum = nums[i] + nums[left] + nums[right].sum < 0, increment left (need a larger value).sum > 0, decrement right (need a smaller value).sum == 0, add the triplet, then skip duplicates for both left and right.