15. 3Sum Medium
Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.
Notice that the solution set must not contain duplicate triplets.
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].
Notice that the order of the output and the order of the triplets does not matter.
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.
Approach
Input: An integer array nums, elements can be positive or negative.
Output: Find all unique triplets [a, b, c] that satisfy a + b + c == 0.
This is a classic problem of sorting + opposite-direction two pointers.
We can sort the array first, then fix the first number nums[i], and use two pointers in the range i+1 to n-1:
Define two pointers:
left = i + 1andright = len(nums) - 1, pointing to candidate positions for the second and third numbers respectively;For each
nums[i]:- If the current number is the same as the previous one (
nums[i] == nums[i - 1]), it means we might generate duplicate triplets, so we skip it; - Use two pointers to iterate through the range
nums[i+1:right], calculate the sum of the three numbers; - If the sum is less than 0, move the left pointer to the right (
left += 1); - If the sum is greater than 0, move the right pointer to the left (
right -= 1); - If the sum equals 0, add it to the result set, and skip the duplicate
nums[left]andnums[right]elements;
- If the current number is the same as the previous one (
When the left and right pointers meet, the processing for the current
iends, and we proceed to the next iteration in the loop.
Essentially, by fixing a number nums[i], we are finding the sum of two remaining numbers that equals -nums[i].
By using sorting + deduplication + two pointers, the time complexity of this solution is O(n^2). It is the optimal standard approach for solving the "3Sum" problem.
Implementation
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort() # Sort the array first to easily use two pointers later
ans = [] # Store the final results
n = len(nums)
for i in range(n - 2): # Iterate over the first number, leave room for j and k
x = nums[i]
# Deduplicate: if the current value is the same as the previous one, skip (to avoid duplicate triplets)
if i > 0 and nums[i] == nums[i - 1]:
continue
# Pruning 1: if the current minimum sum of 3 numbers > 0, no solution is possible later, exit directly
if x + nums[i + 1] + nums[i + 2] > 0:
break
# Pruning 2: if the current maximum sum of 3 numbers < 0, it's impossible to sum to 0, skip current i
if x + nums[-1] + nums[-2] < 0:
continue
# Find combinations where the sum of three numbers is 0 using two pointers from i+1 to the end
j = i + 1
k = n - 1
while j < k:
s = x + nums[j] + nums[k] # Current sum of three numbers
if s < 0:
j += 1 # Sum is too small, move left pointer to increase sum
elif s > 0:
k -= 1 # Sum is too large, move right pointer to decrease sum
else:
ans.append([x, nums[j], nums[k]]) # Found a valid combination
# Skip duplicate second numbers
j += 1
while j < k and nums[j] == nums[j - 1]:
j += 1
# Skip duplicate third numbers
k -= 1
while k > j and nums[k] == nums[k + 1]:
k -= 1
return ans/**
* @param {number[]} nums
* @return {number[][]}
*/
const threeSum = function(nums) {
nums.sort((a, b) => (a - b));
const ans = [];
for (let i = 0; i < nums.length - 2; i++) {
const x = nums[i];
if (i > 0 && nums[i] == nums[i - 1])
continue
if ((x + nums[i + 1] + nums[i + 2]) > 0)
break
if ((x + nums.at(-1) + nums.at(-2)) < 0)
continue
let j = i + 1;
let k = nums.length - 1;
while (j < k) {
const s = x + nums[j] + nums[k];
if (s > 0) {
k--;
} else if (s < 0) {
j++;
} else {
ans.push([x, nums[j], nums[k]]);
j++;
while (j < k && nums[j] == nums[j - 1]) {
j++;
}
k--;
while (j < k && nums[k] == nums[k + 1]) {
k--;
}
}
}
}
return ans;
};Complexity Analysis
- Time Complexity: O(n^2)
- Space Complexity: O(1)