package com.freetymekiyan.algorithms.level.medium; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in * the array which gives the sum of zero. * <p> * Note: The solution set must not contain duplicate triplets. * <p> * For example, given array S = [-1, 0, 1, 2, -1, -4], * <p> * A solution set is: * [ * [-1, 0, 1], * [-1, -1, 2] * ] * Company Tags: Amazon, Microsoft, Bloomberg, Facebook, Adobe * Tags: Array, Two Pointers * Similar Problems: (E) Two Sum, (M) 3Sum Closest, (M) 4Sum, (M) 3Sum Smaller */ class ThreeSum { /** * Two Pointers. * Sort given array first. * Traverse the array with 1 pointer. * Use another 2 pointers from both start(i + 1) and end to find the target. * How to avoid duplicate? Compare current number with the previous one, if same, skip. * How to early pruning? When current number is positive, stop. */ public List<List<Integer>> threeSum(int[] num) { List<List<Integer>> res = new ArrayList<>(); Arrays.sort(num); for (int i = 0; i < num.length - 2; i++) { if (i > 0 && num[i] == num[i - 1]) { continue; // Skip duplicate. } if (num[i] > 0) { break; // Stop at positive integers. } int j = i + 1; // Starts from after i. int k = num.length - 1; // Ends at the end of the array. while (j < k) { if (j > i + 1 && num[j] == num[j - 1]) { // Skip duplicate. j++; continue; } if (num[i] + num[j] > 0) { // Early pruning, already bigger than 0. break; } if (num[i] + num[j] + num[k] < 0) { j++; } else if (num[i] + num[j] + num[k] > 0) { k--; } else { // num[i] + num[j] + num[k] == 0 List<Integer> triplets = new ArrayList<>(); // Add to result. triplets.add(num[i]); triplets.add(num[j]); triplets.add(num[k]); res.add(triplets); j++; // Note to update pointers! k--; } } } return res; } /** * Two pointers. More concise. * Compare first, then move pointer to skip all duplicates. * Note that it compares current position with the next position. * So one more move is needed after that. */ public List<List<Integer>> threeSumB(int[] num) { List<List<Integer>> res = new ArrayList<>(); Arrays.sort(num); for (int i = 0; i < num.length - 2; i++) { if (num[i] > 0) { // Pruning. break; } if (i > 0 && num[i] == num[i - 1]) { continue; } // Two sum search. int lo = i + 1, hi = num.length - 1, sum = 0 - num[i]; if (num[i] + num[lo] > 0) { // Pruning. break; } while (lo < hi) { if (num[lo] + num[hi] == sum) { res.add(Arrays.asList(num[i], num[lo], num[hi])); // Skip duplicates. while (lo < hi && num[lo] == num[lo + 1]) { lo++; } while (lo < hi && num[hi] == num[hi - 1]) { hi--; } // Update pointers. Must happen after duplicates are all skipped. lo++; hi--; } else if (num[lo] + num[hi] < sum) { while (lo < hi && num[lo] == num[lo + 1]) { lo++; } lo++; } else { while (lo < hi && num[hi] == num[hi - 1]) { hi--; } hi--; } } } return res; } }