LeetCode @ 3Sum D3F5

来源:互联网 发布:java编码转换类 编辑:程序博客网 时间:2024/05/17 22:26

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

0 0
原创粉丝点击