4Sum leetCode Java

来源:互联网 发布:最内涵最污的段子 知乎 编辑:程序博客网 时间:2024/05/09 19:26

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
原创粉丝点击