题目:
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)解法:
在之前的TwoSum的那篇博客中已经介绍了从array S中找出两个数使得和为target的算法,当时是用Hash表来实现O(2*n)的算法。
当时需要返回下标,所以不便改变数组顺序,但这一题要求找出数字即可,因此我们可以先对数组进行排序,这样在确定了triplet最小元素为a时,只需要在后面的序列中找到两个数,使得和为-a。
编程之美有一例子就是在有序数组中查找符合条件的数,因此我们可以令i,j分别为数组的头和尾,Xi+Xj < -a时,i++,Xi+Xj>-a时,j--,直到i>=j。这样就可以在O(n)复杂度内找到满足Xi+Xj = -a的元素。
但是考虑{-4,-4,2,2,2,2}这种数组,若仅用上面的方法,会出现大量的重复解,因此,我们需要:
1、在更新第一个元素,即a时,判断之前是否已经检查过
2、在更新i,j时,判断之前的i,j指向的元素是否相同,若相同则继续++或--
3、在提交一组解之后,更新pre_i,pre_j
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class No15_ThreeSum {
public static void main(String[] args){
System.out.println(threeSum(new int[]{-2,0,0,2,2}));
}
public static List<List<Integer>> threeSum(int[] num) {
List<List<Integer>> ret = (List)new ArrayList<ArrayList<Integer>>();
if(num.length == 0) return ret;
Arrays.sort(num);
int k_pre = num[num.length-1]+1;
for(int k=0;k<num.length-2;k++){
if(num[k] == k_pre) continue;
k_pre = num[k];
int i = k+1;
int j = num.length-1;
int i_pre = num[num.length-1]+1;
int j_pre = num[num.length-1]+1;
while(i<j){
if(num[i]+num[j] < -num[k]){
do{i++;}while(i<j && num[i] == i_pre);
if(i<j)
i_pre = num[i];
continue;
}
if(num[i]+num[j] > -num[k]){
do{j--;}while(i<j && num[j] == j_pre);
if(i<j)
j_pre = num[j];
continue;
}
ArrayList<Integer> element = new ArrayList<Integer>();
element.add(num[k]);
element.add(num[i]);
element.add(num[j]);
ret.add(element);
i_pre = num[i];
j_pre = num[j];
do{i++;}while(i<j && num[i] == i_pre);
do{j--;}while(i<j && num[j] == j_pre);
if(i<j){
i_pre = num[i];
j_pre = num[j];
}
}
}
return ret;
}
}