思路1:
排序,二分法查找,前后双指针O(n2*logn)
思路2:
排序,一次外循环+前后指针 O(n2)
package Level3; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * 3Sum * 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. 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. For example, given array S = {-1 0 1 2 -1 -4}, A solution set is: (-1, 0, 1) (-1, -1, 2) * */ public class S15 { public static void main(String[] args) { // int[] num = {-1,0,1,2,-1,-4}; // int[] num = {0,0,0,0}; int[] num = { -2, 0, 1, 1, 2 }; ArrayList<ArrayList<Integer>> ret = threeSum(num); System.out.println(ret.toString()); } // 非递归解法 public static ArrayList<ArrayList<Integer>> threeSum(int[] num) { Set<ArrayList<Integer>> ret = new HashSet<ArrayList<Integer>>(); Arrays.sort(num); for (int i = 0; i < num.length - 1; i++) { // 前指针向后 for (int j = num.length - 1; j > i; j--) { // 后指针向前 int remain = 0 - (num[i] + num[j]); int third = Arrays.binarySearch(num, i + 1, j, remain); if (third >= 0) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(num[i]); list.add(num[third]); list.add(num[j]); ret.add(list); } } } return new ArrayList<ArrayList<Integer>>(ret); } // 递归解法,超时! public static ArrayList<ArrayList<Integer>> threeSum1(int[] num) { Set<ArrayList<Integer>> ret = new HashSet<ArrayList<Integer>>(); Arrays.sort(num); rec(num, 0, num.length - 1, ret); return new ArrayList<ArrayList<Integer>>(ret); } public static void rec(int[] num, int low, int high, Set<ArrayList<Integer>> ret) { if (low >= high) { return; } int remain = 0 - (num[low] + num[high]); int third = Arrays.binarySearch(num, low + 1, high, remain); if (third >= 0) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(num[low]); list.add(num[third]); list.add(num[high]); ret.add(list); rec(num, low + 1, high, ret); rec(num, low, high - 1, ret); } else { if (remain > 0) { rec(num, low + 1, high, ret); } else { rec(num, low, high - 1, ret); } } } }
/* * 3 sum */ public static void find3Numbers(int[] A, int sum) { Arrays.sort(A); int len = A.length; for (int i = 0; i < len; i++) { int l = i + 1; int r = len - 1; while (l < r) { if (A[i] + A[l] + A[r] == sum) { System.out.println(A[i] + ", " + A[l] + ", " + A[r]); return; } else if (A[i] + A[l] + A[r] < sum) { l++; } else { r--; } } } System.out.println("Not found!"); }
Try again:
public static ArrayList<ArrayList<Integer>> threeSum(int[] num) { ArrayList<ArrayList<Integer>> ret = new ArrayList<ArrayList<Integer>>(); if(num.length < 3){ return ret; } Arrays.sort(num); for(int i=0; i<num.length-2 && num[i]<=0; i++){ // Remove duplicates if(i>0 && num[i]==num[i-1]){ continue; } // use two pointer to find b+c=-a int start = i+1, end=num.length-1; while(start < end){ int sum = num[i] + num[start] + num[end]; if(sum < 0){ start++; }else if(sum > 0){ end--; }else{ // find one ArrayList<Integer> al = new ArrayList<Integer>(); al.add(num[i]); al.add(num[start]); al.add(num[end]); ret.add(al); // move left pointer to right and skip duplicates do{ start++; }while(start<end && num[start]==num[start-1]); do{ end--; }while(start<end && num[end]==num[end+1]); } } } return ret; }
注意如何跳过重复元素
public class Solution { public List<List<Integer>> threeSum(int[] num) { Arrays.sort(num); List<List<Integer>> ret = new ArrayList<List<Integer>>(); int len = num.length; int i = 0; while(i <= len-3) { while(i-1 >= 0 && i <= len-3 && num[i] == num[i-1]) { i++; continue; } int left = i+1, right = len-1; while(left < right) { int sum = num[i] + num[left] + num[right]; if(sum == 0) { List<Integer> al = new ArrayList<Integer>(); al.add(num[i]); al.add(num[left]); al.add(num[right]); ret.add(al); do { left++; } while(left<right && num[left]==num[left-1]); do{ right--; } while(left<right && num[right] == num[right+1]); } else if(sum < 0) { left++; } else { right--; } } i++; } return ret; } }