Two Pointers
3-Sum
DESCRIPTION (inspired by Leetcode.com)
Given an input integer array nums, write a function to find all unique triplets [nums[i], nums[j], nums[k]] such that i, j, and k are distinct indices, and the sum of nums[i], nums[j], and nums[k] equals zero. Ensure that the resulting list does not contain any duplicate triplets.
Input:
nums = [-1,0,1,2,-1,-1]
Output:
[[-1,-1,2],[-1,0,1]]
Explanation: Both nums[0], nums[1], nums[2] and nums[1], nums[2], nums[4] both include [-1, 0, 1] and sum to 0. nums[0], nums[3], nums[4] ([-1,-1,2]) also sum to 0.
Since we are looking for unique triplets, we can ignore the duplicate [-1, 0, 1] triplet and return [[-1, -1, 2], [-1, 0, 1]].
The order of the triplets and the order of the elements within the triplets do not matter.
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// Your code goes here
}
}Run your code to see results here
Have suggestions or found something wrong?
Solution
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
3 sum
0 / 18
Explanation
We can leverage the two-pointer technique to solve this problem by first sorting the array. We can then iterate through each element in the array. The problem then reduces to finding two numbers in the rest of the array that sum to the negative of the current element, which follows the same logic as the Two Sum (Sorted Array) problem from the overview.
Result
Since our first triplet sums to 0, we can add it to our result set.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
3 sum
0 / 5
Avoiding Duplicates
As soon as we find a triplet that sums to 0, we can add it to our result set. We then have to move our left and right pointers to look for the next triplet while avoiding duplicate triplets. We can do this by moving the left and right pointers until they point to different numbers than the ones they were pointing to before.
Here we move the left pointer once until it reaches the last -1 in the array. Then, we can move both the left and right pointers so that they both point to new numbers.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
add triplet to output
0 / 2
Here we can do another iteration of the Two Sum problem using the new positions of the left and right pointers.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
move both pointers
0 / 3
At this point our left and right pointers have crossed, so we can move our iterator to the next number in the array.
Avoiding Duplicates II
In this case, since the next number in the array is the same as the previous number, we can skip it. We can do this by moving our iterator until it points to a new number.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
move both pointers
0 / 3
And we're ready to start the Two Sum algorithm again, so we reset our left and right pointers, and start the algorithm.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
initialize pointers
0 / 2
Termination
Our algorithm terminates when i reaches the 3rd to last element in the array (i.e., i < n - 2). This is because we need at least 2 more elements after i for left and right to form a triplet.
public class Solution {public List<List<Integer>> threeSum(int[] nums) {List<List<Integer>> result = new ArrayList<>();// Sort array to enable two-pointer technique and handle duplicatesArrays.sort(nums);// Fix the first element and use two pointers for the remaining twofor (int i = 0; i < nums.length - 2; i++) {// Skip duplicate values for the first element to avoid duplicate tripletsif (i > 0 && nums[i] == nums[i - 1]) {continue;}// Initialize two pointers for the remaining subarrayint left = i + 1;int right = nums.length - 1;// Use two-pointer technique to find pairs that sum to -nums[i]while (left < right) {int total = nums[i] + nums[left] + nums[right];if (total < 0) {// Sum too small, move left pointer right to increase sumleft++;} else if (total > 0) {// Sum too large, move right pointer left to decrease sumright--;} else {// Found a valid tripletresult.add(Arrays.asList(nums[i], nums[left], nums[right]));// Skip all duplicate values to avoid duplicate tripletswhile (left < right && nums[left] == nums[left + 1]) {left++;}while (left < right && nums[right] == nums[right - 1]) {right--;}// Move both pointers to continue searchingleft++;right--;}}}return result;}}
Result
move right pointer backward
0 / 2
What is the time complexity of this solution?
O(m * n)
O(n²)
O(n³)
O(n * logn)