💡 Sorting the array allows us to use two pointers to find pairs that sum to a target efficiently, reducing complexity from cubic to quadratic.
Intuition
Fix one element and use two pointers to find pairs that sum to the negative of the fixed element, skipping duplicates to avoid repeated triplets.
Algorithm
- Sort the input array.
- Iterate over the array with index i from 0 to n-3.
- Skip duplicate elements at i to avoid duplicate triplets.
- Use two pointers, left = i+1 and right = n-1, to find pairs where nums[left] + nums[right] == -nums[i].
- If sum is less than target, move left pointer right; if more, move right pointer left.
- When a valid triplet is found, add it to the result and skip duplicates for left and right pointers.
💡 Sorting and skipping duplicates are key to avoid repeated triplets and reduce search space.
from typing import List
def threeSum(nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for i in range(n):
if i > 0 and nums[i] == nums[i-1]:
continue
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:
res.append([nums[i], nums[left], nums[right]])
left += 1
right -= 1
while left < right and nums[left] == nums[left - 1]:
left += 1
while left < right and nums[right] == nums[right + 1]:
right -= 1
return res
# Driver code
if __name__ == '__main__':
print(threeSum([-1,0,1,2,-1,-4]))
Line Notes
nums.sort()Sorting enables two-pointer technique and duplicate skipping
if i > 0 and nums[i] == nums[i-1]:Skip duplicate fixed elements to avoid repeated triplets
left, right = i + 1, n - 1Initialize two pointers after fixed element
while left < right:Loop to find pairs summing to target
total = nums[i] + nums[left] + nums[right]Calculate current triplet sum
if total < 0: left += 1Sum too small, move left pointer right to increase sum
elif total > 0: right -= 1Sum too large, move right pointer left to decrease sum
else:Found valid triplet
left += 1Move left pointer to next position after finding a triplet
right -= 1Move right pointer to previous position after finding a triplet
while left < right and nums[left] == nums[left - 1]: left += 1Skip duplicates for left pointer to avoid repeated triplets
while left < right and nums[right] == nums[right + 1]: right -= 1Skip duplicates for right pointer to avoid repeated triplets
import java.util.*;
public class ThreeSumTwoPointers {
public static List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> res = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = n - 1;
while (left < right) {
int total = nums[i] + nums[left] + nums[right];
if (total < 0) left++;
else if (total > 0) right--;
else {
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
}
return res;
}
public static void main(String[] args) {
int[] nums = {-1,0,1,2,-1,-4};
System.out.println(threeSum(nums));
}
}
Line Notes
Arrays.sort(nums);Sort array to apply two-pointer technique
if (i > 0 && nums[i] == nums[i - 1]) continue;Skip duplicate fixed elements
int left = i + 1, right = n - 1;Initialize two pointers
while (left < right) {Loop to find pairs
int total = nums[i] + nums[left] + nums[right];Calculate sum of triplet
if (total < 0) left++;Sum too small, move left pointer right
else if (total > 0) right--;Sum too large, move right pointer left
else {Found valid triplet
left++;Move left pointer after finding a triplet
right--;Move right pointer after finding a triplet
while (left < right && nums[left] == nums[left - 1]) left++;Skip duplicates for left pointer
while (left < right && nums[right] == nums[right + 1]) right--;Skip duplicates for right pointer
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
int n = nums.size();
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = n - 1;
while (left < right) {
int total = nums[i] + nums[left] + nums[right];
if (total < 0) left++;
else if (total > 0) right--;
else {
res.push_back({nums[i], nums[left], nums[right]});
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++;
while (left < right && nums[right] == nums[right + 1]) right--;
}
}
}
return res;
}
int main() {
vector<int> nums = {-1,0,1,2,-1,-4};
vector<vector<int>> result = threeSum(nums);
for (auto &triplet : result) {
for (int num : triplet) cout << num << ' ';
cout << '\n';
}
return 0;
}
Line Notes
sort(nums.begin(), nums.end());Sort array to enable two-pointer approach
if (i > 0 && nums[i] == nums[i - 1]) continue;Skip duplicate fixed elements
int left = i + 1, right = n - 1;Initialize two pointers
while (left < right) {Loop to find pairs that sum to target
int total = nums[i] + nums[left] + nums[right];Calculate current triplet sum
if (total < 0) left++;Sum too small, move left pointer right
else if (total > 0) right--;Sum too large, move right pointer left
else {Found valid triplet
left++;Move left pointer after finding a triplet
right--;Move right pointer after finding a triplet
while (left < right && nums[left] == nums[left - 1]) left++;Skip duplicates for left pointer
while (left < right && nums[right] == nums[right + 1]) right--;Skip duplicates for right pointer
function threeSum(nums) {
nums.sort((a, b) => a - b);
const res = [];
const n = nums.length;
for (let i = 0; i < n; i++) {
if (i > 0 && nums[i] === nums[i - 1]) continue;
let left = i + 1, right = n - 1;
while (left < right) {
const total = nums[i] + nums[left] + nums[right];
if (total < 0) left++;
else if (total > 0) right--;
else {
res.push([nums[i], nums[left], nums[right]]);
left++;
right--;
while (left < right && nums[left] === nums[left - 1]) left++;
while (left < right && nums[right] === nums[right + 1]) right--;
}
}
}
return res;
}
// Test
console.log(threeSum([-1,0,1,2,-1,-4]));
Line Notes
nums.sort((a, b) => a - b);Sort array to apply two-pointer technique
if (i > 0 && nums[i] === nums[i - 1]) continue;Skip duplicate fixed elements
let left = i + 1, right = n - 1;Initialize two pointers
while (left < right) {Loop to find pairs
const total = nums[i] + nums[left] + nums[right];Calculate sum of triplet
if (total < 0) left++;Sum too small, move left pointer right
else if (total > 0) right--;Sum too large, move right pointer left
else {Found valid triplet
left++;Move left pointer after finding a triplet
right--;Move right pointer after finding a triplet
while (left < right && nums[left] === nums[left - 1]) left++;Skip duplicates for left pointer
while (left < right && nums[right] === nums[right + 1]) right--;Skip duplicates for right pointer
TimeO(n^2)
SpaceO(n) or O(k) for output storage
Sorting takes O(n log n), then for each element, two pointers scan the rest in O(n), total O(n^2).
💡 For n=1000, about 1 million operations, which is efficient enough for interviews and real use.
Interview Verdict: Accepted
This is the standard efficient solution expected in interviews for 3Sum.