No.18, 4Sum
给定一个数字数组,找出所有四个数字加和等于target的组合。要求输出中不含重复的组合,以及组合中的数字按照从小到大升序排列。
前面做过2Sum,3Sum,这次是4Sum。其实KSum的都可以采用3Sum类似的方法来做,先把数组排序,再定死k-2个数字(即外面有k-2重循环),利用头尾两个指针查找余下的数组中合适的组合,如果比target小,则左指针++,如果比target大,则右指针--。采用这种方法做一般复杂度都是O(nk-1)。当然这里还需要注意处理数组中有重复的情况,需要每一次循环的时候判断是否重复。
public class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List result=new ArrayList<List<Integer>>(); if(nums.length<4){ return result; } Arrays.sort(nums); for(int i=0;i<nums.length;i++){ if(i>0&&nums[i]==nums[i-1]){ continue; } for(int j=i+1;j<nums.length;j++){ if(j>i+1&&nums[j]==nums[j-1]) continue; int begin=j+1; int end=nums.length-1; while(begin<end){ if(begin>j+1&&nums[begin]==nums[begin-1]){ begin++; continue; } int t=nums[i]+nums[j]+nums[begin]+nums[end]; if(t==target){ List<Integer> list=new ArrayList<Integer>(); list.add(nums[i]); list.add(nums[j]); list.add(nums[begin]); list.add(nums[end]); Collections.sort(list); result.add(list); begin++; end--; } else if(t<target){ begin++; } else{ end--; } } } } return result; } }
另外针对4Sum还想了一种方法。将数组中的数字两两搭对,算出它们的和,使用map记录该值以及该数字对,map的value使用list数据结构,这样可以记录多个和相同的数字对。遍历map,查找加和为target的map key,再将其中的数字对组合。看起来比较简单,但是这样做还需要注意的一点,pair1和pair2组合的时候,可能同一个数字同时存在于两个地方,那么这样得到的组合事实上是不存在的,可以在开始计算pair的时候,记录每一个数字出现的次数,再验证结果是否妇存在。下面贴的是这种方法的核心代码,但是我没有处理上述注意的地方,因此结果不正确,仅供参考。
public List<List<Integer>> fourSum(int[] nums, int target) { List result=new ArrayList<List<Integer>>(); Arrays.sort(nums); HashMap map=new HashMap<Integer,List<List<Integer>>>(); for(int i=0;i<nums.length;i++){ if(i>0&&nums[i]==nums[i-1]){ continue; } for(int j=i+1;j<nums.length;j++){ if(j>0&&nums[j]==nums[j-1]){ continue; } int add=nums[i]+nums[j]; List<Integer> pair=new ArrayList<Integer>(); pair.add(nums[i]); pair.add(nums[j]); List list=(List) map.get(add); if(list==null){ list=new ArrayList<List<Integer>>(); map.put(add, list); } list.add(pair); } } Iterator it=map.entrySet().iterator(); while(it.hasNext()){ Entry entry=(Entry) it.next(); int key=(int) entry.getKey(); if(key>=target-key){ continue; } List<List<Integer>> pair1=(List<List<Integer>>)entry.getValue(); List<List<Integer>> pair2=(List<List<Integer>>) map.get(target-key); if(pair2!=null){ for(int i=0;i<pair1.size();i++){ for(int j=0;j<pair2.size();j++){ List<Integer> list=new ArrayList<Integer>(); list.add(pair1.get(i).get(0)); list.add(pair1.get(i).get(1)); list.add(pair2.get(j).get(0)); list.add(pair2.get(j).get(1)); Collections.sort(list); if(!result.contains(list)){ result.add(list); } } } } } return result; }