4Sum leetCode Java

4Sum-leetCode-Java

题目描述

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.

Notes:
  • 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.

Example:

given array S = {1 0 -1 0 -2 2}, and target = 0.
Solution set :
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)

思路

常规思路

将数组排序后,然后从头开始遍历,找到第一个元素nums[i],第二个元素nums[j],剩余的两个的和即为target-nums[i]-nums[j],剩余的两个元素从j+1-nums.length()-1寻找,这里采用两指针,分别指向j+1,length-1,寻找到合适值,就将对应的序列添加到结果中去。
代码如下:

    public static List<Integer> add(int[] a,int i,int j,int k,int m){
        List<Integer> l=new ArrayList<Integer>();
        l.add(a[i]);
        l.add(a[j]);
        l.add(a[k]);
        l.add(a[m]);
        return l;
    }
   public static List<List<Integer>> fourSum(int[] nums, int target) {
        int[] num=nums;
        Arrays.sort(num);//排序
        int len=num.length;
        List<List<Integer>> ll=new ArrayList<List<Integer>>();//保存最终结果
        for(int i=0;i<len-3;i++){
            if(i>0&&num[i]==num[i-1])//避免重复值
                continue;
            for(int j=i+1;j<len-2;j++){
                if(j>i+1&&num[j]==num[j-1])
                    continue;
                int head=j+1,tail=len-1;//定义头指针和尾指针
                int target2=target-num[i]-num[j];
                while(head<tail){
                    int temp=num[head]+num[tail];//记录当前和
                    if(temp<target2)
                        head++;      
                    else if(temp>target2)
                        tail--;
                    else{
                        List<Integer> list=add(num,i,j,head,tail);//将正确序列加入到链表中
                        ll.add(list);
                        int p=head+1;//继续寻找合适的序列,忽略重复值
                        while(p<tail&&num[head]==num[p]){
                            p++;
                        }
                        head=p;
                        int q=tail-1;
                        while(q>head&&num[q]==num[tail]){
                            q--;
                        }
                        tail=q;
                    }
                }
            }
        }
        return ll;
    }

降低时间复杂度的思路

我们可以将数组中所有的和找出来,将sum作为Map的key,将和对应的所有的两元组作为value,这里记录的是元素的在数组中的下标位置,而不是元素值。比如:-1,0,0,1,2
建立的map为:
-1:{0,1}{0,2}
0:{0,3}{0,0}
1:{1,2}{1,3}
2:{1,4}{2,4}
3:{3,4}
还是采用上面提到的方法,为了避免重复,我们先对数组进行排序,然后从头开始遍历,先找到一个元素A,再确定一个元素B ,剩下的和为target-A-B,这里我们就直接从我们建立的map中寻找,这里需要注意的是,可能存在重复值,一是:找到map中下标必须大于B的下标;二是:去除map中重复的value值。

public static List<List<Integer>> fourSum(int[] nums,int target){
        int[] num=nums;
        Arrays.sort(num);
        int len=num.length;
        List<List<Integer>> res=new ArrayList<List<Integer>>();
        Map<Integer,List<int[]>> map=new HashMap<Integer,List<int[]>>();
        //建立两个元素和的映射
        for(int i=0;i<len-1;i++){
            for(int j=i+1;j<len;j++){
                int[] temp=new int[2];
                temp[0]=i;
                temp[1]=j;
                int sum=num[i]+num[j];
                if(!map.containsKey(sum)){
                    List<int[]> list=new ArrayList<int[]>();
                    list.add(temp);
                    map.put(sum, list);
                }else{
                    List<int[]> list=map.get(sum);
                    list.add(temp);
                    map.put(sum, list);
                }
            }
        }
        //寻找合适的结果
        for(int i=0;i<len-3;i++){
            if(i!=0&&num[i]==num[i-1])
                continue;
            for(int j=i+1;j<len-2;j++){
                if(j!=i+1&&num[j]==num[j-1])
                    continue;
                int targetMinus=target-num[i]-num[j];
                //直接从map中寻找是否存在对应的键值
                if(map.containsKey(targetMinus)){
                    List<int[]> list=map.get(targetMinus);
                    boolean flag=false;//记录此次循环是否为第一次添加到结果
                    for(int p=0;p<list.size();p++){
                        int[]  temp=list.get(p);
                        //如果小标小于j忽略,这里是为了避免重复
                        if(temp[0]<=j)
                            continue;
                        //将这一次的结果与该循环中上一次添加的结果对比,如果相同则继续下一次循环
                        if(flag&&res.get(res.size()-1).get(2)==num[temp[0]])
                            continue;
                        List<Integer> l=add(num,i,j,temp[0],temp[1]);
                        res.add(l);
                        flag=true;
                    }
                }
            }
        }
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值