X Tutup
M 1516689562 tags: Array, Two Pointers #### sort array, for loop + two pointer. O(n^2) - 处理duplicate wthin triplets: - 如果最外圈的移动点i重复, 一直顺到结尾的最后一个再用. - 如果是triplet内有重复, 用完start point, 移动到结尾. Previous notes: 注意: 1. 找 value triplets, 多个结果。注意,并非找index。 2. 要升序, 第一层for loop 从最后一个元素挑起, 保证了顺序。 3. 去掉duplicate: check用过的同样的数字,都跳掉。不需要用同样的数字再计算一边已有结果。 步骤: 1. For loop 挑个数字A. 2. 2Sum 出一堆2个数字的结果 3. Cross match 步骤1里面的A. 时间 O(n^2), 两个nested loop 另外, 还是可以用HashMap来做2Sum。稍微短点。还是要注意handle duplicates. ``` /* 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. Example For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2) Note Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c) The solution set must not contain duplicate triplets. Tags Expand Two Pointers Sort Array Facebook *//* Thoughts: Sort the list, do a for loop and two pointer within. Make sure to skip duplicated index value: when 'start' is duplicated, start++ until no duplicates. when i is duplicated, continue in for loop and get to end of last duplicate and use that as i. O(n) * O(n) -> O(n^2) */ class Solution { public List> threeSum(int[] nums) { List> result = new ArrayList<>(); if (nums == null || nums.length == 0) { return result; } Arrays.sort(nums); for (int i = 2; i < nums.length; i++) { if (i + 1 < nums.length && nums[i] == nums[i + 1]) { continue; } int start = 0; int end = i - 1; while (start < end) { if (nums[start] + nums[end] + nums[i] == 0) { result.add(Arrays.asList(nums[start], nums[end], nums[i])); start++; while (start < end && nums[start - 1] == nums[start]) { // skip duplicates start++; } } else if (nums[start] + nums[end] + nums[i] < 0) { start++; } else { end--; } } } return result; } } /* Thoughts: Remember to check for null and edge-soluton. Before everything, Arrays.sort() the given array, in order to effectively handle the duplicates. At 3SUM level, takes 1 element out and do 2SUM on the rest of the front elements of the array. Note, 2SUM has multitple solutions (need to handle duplicates) Cross-match the 2SUM solution with the selected element from 3SUM level. */ public class Solution { public ArrayList> threeSum(int[] numbers) { ArrayList> rst = new ArrayList>(); if (numbers == null && numbers.length <= 2) {// Length at least >= 3 return rst; } Arrays.sort(numbers);//Sort in order to handle duplicates for (int i = numbers.length - 1; i >= 2; i--) {// i >=2 because at least 3 element in result; starting from end, ensures non-descending order if (i < numbers.length - 1 && numbers[i] == numbers[i + 1]) { continue;//The case of numbers[i + 1]: should have already covered all possibilities of the case numbers[i], so safe to skip } ArrayList> twoSum = calTwoSum(numbers, i - 1, 0 - numbers[i]);//Pick the 3rd element numbers[i] for (int j = 0; j < twoSum.size(); j++) {//Find two sum of rest-front elements. Cross add them with numbers[i] twoSum.get(j).add(numbers[i]); } rst.addAll(twoSum); } return rst; } //Two Sum. Multiple answer public ArrayList> calTwoSum(int[] num, int end, int target) { ArrayList> rst = new ArrayList>(); int left = 0; int right = end; while (left < right) { if (num[left] + num[right] == target) { ArrayList match = new ArrayList(); match.add(num[left]); match.add(num[right]); rst.add(match); left++; right--; //For unique number A, there is only 1 unique number B such that A + B == target. //Therefore, once found the match, erase all numbers that's equal to A or equal to B while (left < right && num[left] == num[left - 1]) { left++; } while (left < right && num[right] == num[right + 1]) { right--; } } else if (num[left] + num[right] < target) {//Since int[] num is sorted: move L to right-side to get larger value. left++; } else { right--; } } return rst; } } /* Thoughts: Exact same approach, except using HashMap in 2Sum */ //With HashMap 2Sum public class Solution { public ArrayList> threeSum(int[] numbers) { ArrayList> rst = new ArrayList>(); if (numbers == null && numbers.length <= 2) {// Length at least >= 3 return rst; } Arrays.sort(numbers);//Sort in order to handle duplicates for (int i = numbers.length - 1; i >= 2; i--) {// i >=2 because at least 3 element in result; starting from end, ensures non-descending order if (i < numbers.length - 1 && numbers[i] == numbers[i + 1]) { continue;//The case of numbers[i + 1]: should have already covered all possibilities of the case numbers[i], so safe to skip } ArrayList> twoSum = calTwoSum(numbers, i - 1, 0 - numbers[i]);//Pick the 3rd element numbers[i] for (int j = 0; j < twoSum.size(); j++) {//Find two sum of rest-front elements. Cross add them with numbers[i] twoSum.get(j).add(numbers[i]); } rst.addAll(twoSum); } return rst; } //Two Sum. Multiple answer, with HashMap public ArrayList> calTwoSum(int[] num, int end, int target) { ArrayList> rst = new ArrayList>(); ArrayList match; HashMap map = new HashMap(); for (int i = 0; i <= end; i++) { if (map.containsKey(num[i])) { match = new ArrayList(); match.add(num[map.get(num[i])]); match.add(num[i]); if (!rst.contains(match)) { rst.add(new ArrayList(match)); } } else { map.put(target - num[i], i); } //Skip duplicate if (i < end && num[i] == num[i + 1]) { continue; } } return rst; } } /* From LeetCode Solution Thoughts: sort list. O(nLogn) end: n^2 for (i = 0 ~ n) { int target = 0 - nums[i]; while (start + 1 < end) { start + end == target { rst.add(i, star, end); keep looking: start ++, end-- } else start + end < target? start++ else end--; } } } Note: Check duplicates. Compute a unique string to savei set */ public class Solution { public List> threeSum(int[] nums) { List> rst = new ArrayList>(); if (nums == null || nums.length == 0) { return rst; } Arrays.sort(nums); HashSet set = new HashSet(); //use old target to check duplicates. instead of set. for (int i = 0; i < nums.length - 2; i++) { int target = 0 - nums[i]; int start = i + 1; int end = nums.length - 1; ArrayList list = new ArrayList(); while (start < end) { if (nums[start] + nums[end] == target && !set.contains(nums[i] + "," + nums[start] + "," + nums[end])) { list.add(nums[i]); list.add(nums[start]); list.add(nums[end]); rst.add(list); set.add(nums[i] + "," + nums[start] + "," + nums[end]); list = new ArrayList(); start++; end--; } else if (nums[start] + nums[end] < target) { start++; } else { end--; } }//end while } return rst; } } ```
X Tutup