LeetCode @ 3Sum D3F5

Given an array S of n integers, are there elements abc 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)


brute force时间复杂度为O(n^3)。这道题和Two Sum有所不同,使用哈希表的解法并不是很方便,因为结果数组中元素可能重复.
如果不排序对于重复的处理将会比较麻烦,因此这道题一般使用排序之后夹逼的方法,总的时间复杂度为O(n^2+nlogn)=(n^2),空间复杂度是O(n),

public class Solution {
    public ArrayList<ArrayList<Integer>> threeSum(int[] num) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();  
        if(num==null || num.length<=2)  
            return res;  
        Arrays.sort(num);  
        for(int i=num.length-1;i>=2;i--){          //【注意3】
            if(i<num.length-1 && num[i]==num[i+1]) //【注意3】
                continue;  
            ArrayList<ArrayList<Integer>> curRes = twoSum(num,i-1,-num[i]);  
            for(int j=0;j<curRes.size();j++)
                curRes.get(j).add(num[i]);
            res.addAll(curRes);  
        }  
        return res;  
    }
    
    private ArrayList<ArrayList<Integer>> twoSum(int[] num, int end, int target){
        //【注意1】此处定义2D-list和twoSum还是threeSum无关,而是和是否有多重解有关,因为之前的TwoSum不考虑多重解
		ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
        int left=0;
        int right= end;
        while(left<right){
            if(num[left]+num[right]==target){                     //case(1)
                ArrayList<Integer> tempRes = new ArrayList<Integer>();          //【注意1】
                tempRes.add(num[left]); //【注意2】
                tempRes.add(num[right]);//【注意2】
                res.add(tempRes);
                left++; //【注意3】
                right--;//【注意3】
                while(left<right && num[left]==num[left-1])  //【注意3】
                    left++;
                while(left<right && num[right]==num[right+1])//【注意3】
                    right--;
            }
            else if(num[left]+num[right]<target)                  //case(2),先写left右移的case调理会比较清楚
                left++;
            else                                                  //case(3)
                right--;
        }
        return res;
    }
}

【注意1】当解是一个ArrayList,且有多解的题,定义2D-ArrayList。
且之前定义的2D-ArrayList不用急于定义内部的ArrayList元素,在此行用到时候在定义。
【注意2】注意2D-ArrayList的范型,OJ时候出现范型的compile error。
【注意3】算是一个编程技巧。以前写程序时候,不知道比较两个相邻元素,使用A[i]==A[i+1],还是A[i-1]==A[i]。
此处总结一下:
(1)首先left++,才有了 left-1 的存在;其次比较时候考虑时间顺序:当前left == 之前left( 既 left-1 的状态)
“left++;   num[left]==num[left - 1]”
(2)首先right--,才有了 right+1 的存在;其次比较时候考虑时间顺序:当前right == 之前right( 既 right+1 的状态)
“right--;  num[right]==num[right + 1]”

【后记】此法可以推广到Ksum,先排序,然后做num.length-2 次循环,最内层循环左右夹逼。
        时间复杂度是 max( nlogn , n^(k-1) ),排序和循环,谁的O高阶取谁。
【后记】另一种较简洁的代码:yunduomo的3Sum

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值