2.1.10 4Sum

Link: https://oj.leetcode.com/problems/4sum/

Given an array S of n integers, are there elements abc, 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)
Approach I: 我的思路:同3Sum, 先排序,然後左右夾逼。

Time: O(n^3)

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        Arrays.sort(num);
        for(int i = 0; i < num.length; i++){
            if(i != 0 && num[i] == num[i-1]) continue;
            int remain = target - num[i];
            ArrayList<Integer> item = new ArrayList<Integer>();
            item.add(num[i]);
            ArrayList<ArrayList<Integer>> sub = threeSum(num, i+1, remain);
            for(int j = 0; j <sub.size(); j++){
                for(int k = 0; k < sub.get(j).size();k++){
                    item.add(sub.get(j).get(k));
                }
            }
            result.add(item);
        }
        return result;
    }
    
    public ArrayList<ArrayList<Integer>> threeSum(int[] num, int l, int target){
        ArrayList<ArrayList<Integer>> sub = new  ArrayList<ArrayList<Integer>> ();
        for(int i = l; i < num.length; i++){
            if(i != l && num[i] == num[i-1]) continue;
            int j = i+1;
            int k = num.length - 1;
            while(j < k){
                if(num[j]+num[k] == target - num[i]){
                    ArrayList<Integer> list = new ArrayList<Integer>();
                    list.add(num[i]);
                    list.add(num[j]);
                    list.add(num[k]);
                    sub.add(list);
                    j++;
                    k--;
                    while(j < k && num[j] == num[j-1]){
                        j++;
                    }
                    while(j < k && num[k] == num[k+1]){
                        k--;
                    }
                }
                else if(num[j]+num[k] < target -num[i]){
                    j++;
                }
                else{
                    k--;
                }
            }
        }
        return sub;
    }
}
I don't know why did I have wrong answer:

Input: [0], 0
Output: [[0]]
Expected: []

但是寫成這樣就可以過:516ms

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
         if(num==null||num.length==0)
            return result;
        Arrays.sort(num);
        for(int l = 0; l < num.length;l++){
            if(l != 0 && num[l] == num[l-1]) continue;
            for(int i = l+1; i < num.length; i++){
                if(i != l+1 && num[i] == num[i-1]) continue;
                int j = i+1;
                int k = num.length - 1;
                while(j < k){
                    if(num[l] + num[i] + num[j]+num[k] == target){
                        ArrayList<Integer> list = new ArrayList<Integer>();
                        list.add(num[l]);
                        list.add(num[i]);
                        list.add(num[j]);
                        list.add(num[k]);
                        result.add(list);
                        j++;
                        k--;
                        while(j < k && num[j] == num[j-1]){
                            j++;
                        }
                        while(j < k && num[k] == num[k+1]){
                            k--;
                        }
                    }
                    else if(num[l] + num[i] + num[j]+num[k] < target){
                        j++;
                    }
                    else{
                        k--;
                    }
                }
            }
        }
        return result;
    }
}

Approach II: 4Sum = TwoSum + TwoSum. 先找出所有的pair (O(n^2)),然後對這些pair進行TwoSum。

Time = O(n^2log(n^2))= O(n^2logn)

I tried to complete the code from Ref:

but didn't finish. 

public class Solution {
   public class Tuple{
        ArrayList<Integer> val;
        public Tuple(ArrayList<Integer> val){
            this.val = val;
        }
    }
    
    public class Pair{
        Nodes[] nodes;
        public Pair (Node n1, Node n2){
            nodes = new Node[2];
            nodes[0] = n1;
            nodes[1] = n2;
        }
        publc int getSum(){
            return nodes[0].val + nodes[1].val;
        }
    }
    
    public class Node{
        int index;
        int val;
        public Node(int index, int val){
            this.index = index;
            this.val = val;
        }
    }
    
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
         if(num==null||num.length==0)
            return result;
        Arrays.sort(num);
        //save all the pairs into an ArrayList
        ArrayList<Pair> pairs = new ArrayList<Pair>();
        Pair p = null;
        for(int i = 0; i < num.length; i++){
            Node n1 = new Node(i, num[i]);
            for(int j = i+1; j < num.length; j++){
                Node n2 = new Node(j, num[j]);
                p = new Pair(n1, n2);
                pairs.add(p);
            }
        }
        pairs.sort(pair, new Comparator<Pair>(){
            public int compare(Pair p1, Pair p2){
                if(p1.getSum() < p2.getSum()){
                    return 1;
                }
                else if(p1.getSum() == p2.getSum()){
                    return 0;
                }
                else return -1;
            }
        }
        result = twoSum(pairs, target);
        return result;
    }
    
    private ArrayList<ArrayList<Integer>> twoSum(ArrayList<Pair> pairs, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        HashSet<Tuple> set = new HashSet<Tuple>();
        int i = 0;
        int j = pairs.size()-1;
        while(i < j){
            int sum = pairs.get(i).getSum() + pairs.get(i).getSum();
            if(sum == target){
                ArrayList<Integer> list = new ArrayList<Integer>();
                if(checkDup(pairs.get(i), pairs.get(i))){
                    list.add(pairs.get(i).nodes[0].val);
                    list.add(pairs.get(i).nodes[1].val);
                    list.add(pairs.get(j).nodes[0].val);
                    list.add(pairs.get(j).nodes[1].val);
                    Tuple t = new Tuple(list);
                    if(!set.contains(t)){
                        set.add(t);
                        result.add(list);
                    }
                    
                }
               
            }
            else if (sum < target){
                i++;
            }
            else{
                j--;
            }
        }
    }
    
    private boolean checkDup(Pair p1, Pair p2){
        if(p1.node[0].index == p2.nodes[0].index || p1.node[0].index == p2.nodes[1].index){
            return false;
        }
        if(p1.node[1].index == p2.nodes[0].index || p1.node[1].index == p2.nodes[1].index){
            return false;
        }
        return true;
    }
        
    
}

Pass OJ version:

Ref: http://www.lifeincode.net/programming/leetcode-two-sum-3-sum-3-sum-closest-and-4-sum-java/

Note: 雖然這個解法的時間複雜度小,但用時更長:804ms

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>();
        Arrays.sort(num);
       
        //create a hashmap of <sum, (idx1, idx2)>
        HashMap<Integer, ArrayList<ArrayList<Integer>>> dict = new HashMap<Integer, ArrayList<ArrayList<Integer>>>();
        ArrayList<ArrayList<Integer>> pairs = new ArrayList<ArrayList<Integer>>();
        for(int i = 0; i < num.length - 1; i++){
            for(int j = i+1; j < num.length; j++){
                ArrayList<Integer> pair = new ArrayList<Integer>(2);
                pair.add(i);
                pair.add(j);
                int sum = num[i] + num[j];
                if(!dict.containsKey(sum)){
                    pairs = new ArrayList<ArrayList<Integer>>();
                    pairs.add(pair);
                    dict.put(sum, pairs);
                }
                else{
                    pairs = dict.get(sum);
                    pairs.add(pair);
                }
            }
        }
        //create hashset to prevent duplicate results
        HashSet<ArrayList<Integer>> set = new HashSet<ArrayList<Integer>> ();
        for(Integer sum : dict.keySet()){//Note: Remember this line's format!
            pairs = dict.get(sum);
            if(dict.containsKey(target - sum)){//found the other half
               if(target - sum == sum && dict.get(sum).size()==1){//6=3+3.why is dict.get(sum).size()==1 possible? 
                   continue;
               } 
               ArrayList<ArrayList<Integer>> otherPairs = dict.get(target - sum);
               for(ArrayList<Integer> p1 : pairs){
                   for(ArrayList<Integer> p2 : otherPairs){
                       if(p1 == p2) continue;
                       if(p1.contains(p2.get(0)) ||p1.contains(p2.get(1))){
                           continue;
                       } 
                       ArrayList<Integer> tmpResult = new ArrayList<Integer>(4);
                       tmpResult.add(num[p1.get(0)]);
                       tmpResult.add(num[p1.get(1)]);
                       tmpResult.add(num[p2.get(0)]);
                       tmpResult.add(num[p2.get(1)]);
                       //sort the list since require non-descending order
                       Collections.sort(tmpResult);
                       set.add(tmpResult);
                   }
               }
            }
        }
        result.addAll(set);
        return result;
       
    }
}

注意:如果不用hashset,而是直接把結果放到arraylist裏,會出現錯誤。爲什麼?

Input: [0,0,0,0], 0
Output: [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
Expected: [[0,0,0,0]]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章