首页 > 代码库 > Leetcode: 4Sum

Leetcode: 4Sum

Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.Note:Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)The solution set must not contain duplicate quadruplets.    For example, given array S = {1 0 -1 0 -2 2}, and target = 0.    A solution set is:    (-1,  0, 0, 1)    (-2, -1, 1, 2)    (-2,  0, 0, 2)

可以按照3Sum的思路来做,并以此类推,KSum的复杂度就是O(N^(k-1)). 在3Sum外面再套一层循环,相当于N次求3Sum

 1 public class Solution { 2     public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) { 3         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); 4         if (num==null || num.length==0) return res; 5         Arrays.sort(num); 6         for (int i=num.length-1; i>=3; i--) { 7             if (i<num.length-1 && num[i]==num[i+1]) continue; 8             ArrayList<ArrayList<Integer>> sets = threeSum(0, i-1, num, target-num[i]); 9             for (int ii=0; ii<sets.size(); ii++) {10                 ArrayList<Integer> temp = sets.get(ii);11                 temp.add(num[i]);12             }13             res.addAll(sets);14         }15         return res;16     }17     18     public ArrayList<ArrayList<Integer>> threeSum(int start, int end, int[] num, int target) {19         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();20         for (int j=end; j>=2; j--) {21             if (j<end && num[j]==num[j+1]) continue;22             ArrayList<ArrayList<Integer>> sets = twoSum(0, j-1, num, target-num[j]);23             for (int jj=0; jj<sets.size(); jj++) {24                 ArrayList<Integer> temp = sets.get(jj);25                 temp.add(num[j]);26             }27             res.addAll(sets);28         }29         return res;30     }31     32     public ArrayList<ArrayList<Integer>> twoSum(int l, int r, int[] num, int target) {33         ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();34         while (l < r) {35             if (num[l]+num[r] == target) {36                 ArrayList<Integer> set = new ArrayList<Integer>();37                 set.add(num[l]);38                 set.add(num[r]);39                 res.add(new ArrayList<Integer>(set));40                 l++;41                 r--;42                 while (l<r && num[l] == num[l-1]) {43                     l++;44                 }45                 while (l<r && num[r] == num[r+1]) {46                     r--;47                 }48             }49             else if (num[l]+num[r] < target) {50                 l++;51             }52             else {53                 r--;54             }55         }56         return res;57     }58 }

(未深究)网上还看到一种方法,就是如果想那么时间复杂度更好的话,其实我们可以考虑用二分法的思路,如果把所有的两两pair都求出来,然后再进行一次Two Sum的匹配,我们知道Two Sum是一个排序加上一个线性的操作,并且把所有pair的数量是O((n-1)+(n-2)+...+1)=O(n(n-1)/2)=O(n^2)。所以对O(n^2)的排序如果不用特殊线性排序算法是O(n^2*log(n^2))=O(n^2*2logn)=O(n^2*logn),算法复杂度比上一个方法的O(n^3)是有提高的。
思路虽然明确,不过细节上会多很多情况要处理。首先,我们要对每一个pair建一个数据结构来存储元素的值和对应的index,这样做是为了后面当找到合适的两对pair相加能得到target值时看看他们是否有重叠的index,如果有说明它们不是合法的一个结果,因为不是四个不同的元素。接下来我们还得对这些pair进行排序,所以要给pair定义comparable的函数。最后,当进行Two Sum的匹配时因为pair不再是一个值,所以不能像Two Sum中那样直接跳过相同的,每一组都得进行查看,这样就会出现重复的情况,所以我们还得给每一个四个元素组成的tuple定义hashcode和相等函数,以便可以把当前求得的结果放在一个HashSet里面,这样得到新结果如果是重复的就不加入结果集了。

 1 private ArrayList<ArrayList<Integer>> twoSum(ArrayList<Pair> pairs, int target){ 2     HashSet<Tuple> hashSet = new HashSet<Tuple>(); 3     int l = 0; 4     int r = pairs.size()-1; 5     ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>(); 6     while(l<r){ 7         if(pairs.get(l).getSum()+pairs.get(r).getSum()==target) 8         { 9             int lEnd = l;10             int rEnd = r;11             while(lEnd<rEnd && pairs.get(lEnd).getSum()==pairs.get(lEnd+1).getSum())12             {13                 lEnd++;14             }15             while(lEnd<rEnd && pairs.get(rEnd).getSum()==pairs.get(rEnd-1).getSum())16             {17                 rEnd--;18             }19             for(int i=l;i<=lEnd;i++)20             {21                 for(int j=r;j>=rEnd;j--)22                 {23                     if(check(pairs.get(i),pairs.get(j)))24                     {25                         ArrayList<Integer> item = new ArrayList<Integer>();26                         item.add(pairs.get(i).nodes[0].value);27                         item.add(pairs.get(i).nodes[1].value);28                         item.add(pairs.get(j).nodes[0].value);29                         item.add(pairs.get(j).nodes[1].value);30                         //Collections.sort(item);31                         Tuple tuple = new Tuple(item);32                         if(!hashSet.contains(tuple))33                         {34                             hashSet.add(tuple);35                             res.add(tuple.num);36                         }37                     }                        38                 }39             }40             l = lEnd+1;41             r = rEnd-1;42         }43         else if(pairs.get(l).getSum()+pairs.get(r).getSum()>target)44         {45             r--;46         }47         else{48             l++;49         }50     }51     return res;52 }53 private boolean check(Pair p1, Pair p2)54 {55     if(p1.nodes[0].index == p2.nodes[0].index || p1.nodes[0].index == p2.nodes[1].index)56         return false;57     if(p1.nodes[1].index == p2.nodes[0].index || p1.nodes[1].index == p2.nodes[1].index)58         return false;59     return true;60 }

 

Leetcode: 4Sum