3sum

描述:

给定一个整形无序数组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;
		}

  

原文地址:https://www.cnblogs.com/K-artorias/p/7909071.html