思路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;
}
}