[Leetcode]4Sum随记

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;
    }
View Code

 

转载于:https://www.cnblogs.com/lilylee/p/5228632.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值