描述:
给定一个整形无序数组a,其中元素可重复,在a中找出所有的{a, b, c}满足条件a+b+c=0,且结果不可以重复
例如,给定数组S = [-1,0,1,2,-1,-4], 答案: [ [-1,0,1], [-1,-1,2] ]
思考过程:
在解决这个题时,我一直考虑怎么才能避免重复,因为这是个无序数组,我最先想到的是匹配已有结果,但是这样会超级复杂,解决方法一定不是这样的。那么既然无序的不好办,把它变成有序的如何?ok就是这样。用Arrays.sort(a),就可以让数组有序化。
本着先做出来再注意时间复杂度的想法,下面是我的方法,逻辑正确,时间超限制了:
public static List<List<Integer>> threeSum(int[] nums) { Arrays.sort(nums); List<List<Integer>> results = new ArrayList(); int a,b,c,l=nums.length; for(int i=0; i<l-2; i++){ a=nums[i]; for(int j=i+1; j<l-1; j++){ b=nums[j]; for(int n=j+1; n<l; n++){ c=nums[n]; //由于nums是顺序的,所以当c>(0-a-b)条件满足时且还未匹配到结果时,此次第三层循环就不会有结果了,直接break if(c>(0-a-b)) break; if(a+b+c == 0){ List<Integer> result = new ArrayList(); result.add(a); result.add(b); result.add(c); results.add(result); break; } } //避免第二个数重复出现 while((j+1<l-1) && (b == nums[j+1])){ j++; } } //避免第一个数重复出现 while((i+1<l-2) && (a == nums[i+1])){ i++; } } return results; }
下面是leetcode大神的方法:
public List<List<Integer>> threeSum1(int[] num) { Arrays.sort(num); List<List<Integer>> res = new LinkedList<>(); //这里计算的是第一个数,第一个数是从第0位到第length-2位 for (int i = 0; i < num.length-2; i++) { //当i++时要避免num[i]=num[i++],否则会出现重复的集合 if (i == 0 || (i > 0 && num[i] != num[i-1])) { //计算出了第二位数的循环区间(lo,hi)和第二第三位数的加和sum int lo = i+1, hi = num.length-1, sum = 0 - num[i]; //这里计算的是第二个数,第二个数每次都要在第一位数的后一位开始,即i+1位到第length-1位 //循环里做的事情是:当第一位数一定时,找出所有可能的第二和第三位数 while (lo < hi) { //当第二个和第三个数符合题目条件时,那么上下线都应该同时移动 if (num[lo] + num[hi] == sum) { res.add(Arrays.asList(num[i], num[lo], num[hi])); //两个while功能是避免第二和第三个数的重复出现 while (lo < hi && num[lo] == num[lo+1]) lo++; while (lo < hi && num[hi] == num[hi-1]) hi--; lo++; hi--; } //如果不符合条件,就应该按照实际情况只移动上限或者下限 else if (num[lo] + num[hi] < sum) lo++; else hi--; } } } return res; }