Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] where nums[i] + nums[j] + nums[k] == 0, and the indices i, j and k are all distinct.
The output should not contain any duplicate triplets. You may return the output and the triplets in any order.
Example 1:
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]Explanation:nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Example 2:
Input: nums = [0,1,1]
Output: []Explanation: The only possible triplet does not sum up to 0.
Example 3:
Input: nums = [0,0,0]
Output: [[0,0,0]]Explanation: The only possible triplet sums up to 0.
Constraints:
3 <= nums.length <= 1000-10^5 <= nums[i] <= 10^5
You should aim for a solution with O(n^2) time and O(1) space, where n is the size of the input array.
A brute force solution would be to check for every triplet in the array. This would be an O(n^3) solution. Can you think of a better way?
Can you think of an algorithm after sorting the input array? What can we observe by rearranging the given equation in the problem?
We can iterate through nums with index i and get nums[i] = -(nums[j] + nums[k]) after rearranging the equation, making -nums[i] = nums[j] + nums[k]. For each index i, we should efficiently calculate the j and k pairs without duplicates. Which algorithm is suitable to find j and k pairs?
To efficiently find the j and k pairs, we run the two pointer approach on the elements to the right of index i as the array is sorted. When we run two pointer algorithm, consider j and k as pointers (j is at left, k is at right) and target = -nums[i], if the current sum num[j] + nums[k] < target then we need to increase the value of current sum by incrementing j pointer. Else if the current sum num[j] + nums[k] > target then we should decrease the value of current sum by decrementing k pointer. How do you deal with duplicates?
When the current sum nums[j] + nums[k] == target add this pair to the result. We can move j or k pointer until j < k and the pairs are repeated. This ensures that no duplicate pairs are added to the result.
Before attempting this problem, you should be comfortable with:
The brute-force approach simply tries every possible triplet.
Since we check all combinations (i, j, k) with i < j < k, we are guaranteed to find all sets of three numbers that sum to zero.
Sorting helps keep the triplets in order and makes it easier to avoid duplicates by storing them in a set.
res to store unique triplets.i,j > i,k > j,nums[i] + nums[j] + nums[k] == 0.class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = set()
nums.sort()
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
for k in range(j + 1, len(nums)):
if nums[i] + nums[j] + nums[k] == 0:
tmp = [nums[i], nums[j], nums[k]]
res.add(tuple(tmp))
return [list(i) for i in res]Where is the number of triplets and is the length of the given array.
After sorting the array, we can fix two numbers and look for the third number that completes the triplet.
To do this efficiently, we use a hash map that stores how many times each number appears.
As we pick the first and second numbers, we temporarily reduce their counts in the map so we don't reuse them.
Then we check whether the needed third value still exists in the map.
Sorting also helps us skip duplicates easily so we only add unique triplets.
count for all numbers.res for storing valid triplets.i:nums[i] (so it won't be reused).j > i:nums[j].target = -(nums[i] + nums[j])target still has a positive count, add the triplet.js, restore the counts for the second loop by adding back the decremented values.res containing all found triplets.class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
count = defaultdict(int)
for num in nums:
count[num] += 1
res = []
for i in range(len(nums)):
count[nums[i]] -= 1
if i and nums[i] == nums[i - 1]:
continue
for j in range(i + 1, len(nums)):
count[nums[j]] -= 1
if j - 1 > i and nums[j] == nums[j - 1]:
continue
target = -(nums[i] + nums[j])
if count[target] > 0:
res.append([nums[i], nums[j], target])
for j in range(i + 1, len(nums)):
count[nums[j]] += 1
return resAfter sorting the array, we can fix one number and then search for the other two using the two-pointer technique.
Sorting helps in two ways:
For each fixed number a, we place two pointers:
l starts just after i,r starts at the end.If the current sum is too large, we move r left to reduce it.
If the sum is too small, we move l right to increase it.
When the sum is exactly zero, we record the triplet and skip duplicates.
i:a = nums[i].a > 0, break (all remaining numbers are positive).l = i + 1r = len(nums) - 1l < r:threeSum = a + nums[l] + nums[r].threeSum > 0, move r left.threeSum < 0, move l right.threeSum == 0:class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
nums.sort()
for i, a in enumerate(nums):
if a > 0:
break
if i > 0 and a == nums[i - 1]:
continue
l, r = i + 1, len(nums) - 1
while l < r:
threeSum = a + nums[l] + nums[r]
if threeSum > 0:
r -= 1
elif threeSum < 0:
l += 1
else:
res.append([a, nums[l], nums[r]])
l += 1
r -= 1
while nums[l] == nums[l - 1] and l < r:
l += 1
return resWhere is the number of triplets and is the length of the given array.
A common mistake is not properly skipping duplicate values, which leads to duplicate triplets in the result. After sorting, when you find a valid triplet, you must skip over all identical values for the first element (outer loop) and the left pointer. Failing to do this causes wrong answers on inputs like [-1, -1, 0, 1, 1].
The two-pointer approach only works correctly on a sorted array. Without sorting, moving pointers based on sum comparisons does not guarantee you will find all valid triplets. Always sort the input array before applying the two-pointer technique.
When the first element nums[i] is positive, all remaining elements are also positive (since the array is sorted), so no triplet can sum to zero. However, incorrectly breaking when nums[i] >= 0 instead of nums[i] > 0 misses cases like [0, 0, 0]. The break condition should be nums[i] > 0, not nums[i] >= 0.