Thursday, September 12, 2013

4Sum

 Q:
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.
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) 

A:
 ---------------4th pass--------------------------------------
思路很简单,就是把4 sum 换成3 sum,然后加入即可。

public class Solution {
    public List<List<Integer>> fourSum(int[] num, int target) {
        List<List<Integer>> all = new LinkedList<List<Integer>>();
        Arrays.sort(num);
        if(num==null || num.length<4)
            return all;
        for(int i =0;i<num.length-3;i++){
            if(i!=0 && num[i] == num[i-1])// unique for the first element
                continue;
            List<List<Integer>> subAll = threeSum(num,i+1,target-num[i]);
            for(List<Integer> al : subAll)
                al.add(0,num[i]);
            all.addAll(subAll);
        }
        return all;
    }
    private List<List<Integer>> threeSum(int[] num, int start, int target) {
        List<List<Integer>> all = new LinkedList<List<Integer>>();
        for(int i1 = start;i1<num.length-2;i1++){
            if(i1!=start && num[i1] == num[i1-1])
                continue;
            int i2 = i1+1,i3=num.length-1;
            while(i2<i3){
                while(i3-1>i2 && num[i1]+num[i2]+num[i3]>target)
                    i3--;
                if(num[i1]+num[i2]+num[i3] == target){
                    List<Integer> al = new LinkedList<Integer>();
                    al.add(num[i1]);
                    al.add(num[i2]);
                    al.add(num[i3]);
                    all.add(al);
                }
                // update i2 to a new value
                while(i2+1<i3 && num[i2] == num[i2+1])
                    i2++;
                i2++;
            }
        }
        return all;
    }
}

Mistakes:
这里,忘了update i2 into a new value,


--------------------1st pass ----------------------
Idea: partition the p1, p2, p3, p4 into two groups,
p1 with p4 as the outer round(但这个不是linear的, 哎,原以为一定是linear的, 总共也是O(n^2)的,所以白花了好几个小时。

and p2 with p3 as the inner round.


public class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> all = new LinkedList<List<Integer>>();
        Arrays.sort(nums);
        for(int i0=0;i0 < nums.length -3;i0++){
            if(i0>0 && nums[i0] == nums[i0-1])
                continue;
            for(int i2=i0+1;i2<nums.length-2;i2++){
                if(i2>i0+1 && nums[i2] == nums[i2-1])
                    continue;
                int j = i2+1, k = nums.length-1;
                while(j<k){
                    if(nums[i0] + nums[i2] + nums[j] + nums[k] == target){
                        List<Integer> al = new LinkedList<Integer>();
                        al.add(nums[i0]);
                        al.add(nums[i2]);
                        al.add(nums[j]);
                        al.add(nums[k]);
                        all.add(al);
                    }
                    while(j< k &&  nums[i0] + nums[i2] + nums[j] + nums[k] == target )
                        j++;
                    if(j< k &&  nums[i0] + nums[i2] + nums[j] + nums[k] < target)
                        j++;
                    else
                        k--;
                }
            }
        }
        return all;
        
    }
}


Mistakes:
1; 光顾得上p1,p4不要重复了,忘了把p2,p3也不能重复
2: 光想到,对想同的p1,  先只考虑最后一个p1的值。了,。但是这样,就导致了,相同的值,不能作为p2了。应该是先把读取,然后,再移动到下一个不同的index上。
 哎~~~~~头脑还是不够清晰阿
3: 哎, 如果target 是0, 那【....0,0,0,0....]也行的阿。 你这么跳,就不行了。 所以说,4sum不能像2sum那么跳。
哎~~~~~~~~~~~~~~~~~~ SB Tiger
4:  inner circle 中,(就是对于p2 , p3 的twoSum()方法里, 应该是p3>p2+1的时候,才是p3--;  否则,仅仅是p3>p2, 就会导致p3==p2

-------------------------------------第二遍---------------------想加速,就先把所有的potentiao sum value 都计算了,然后,记录下了要增加达到他们的地址。-------------可是,这样,对于重复的问题,就很难办, 比较讨厌。 还是不用这个方法了。。  乖乖地用O(n^3)的方法吧。


5:   2 pointer的时候,在第二个while里面,不要忘记判断下标越界。

6:  do {} while() 后面要加分号 ;
7:  第一个while中,应该是while(p0+3 <= p3) ,而不是简单的小于
8:  when updating p1, we originally wrote
    // update p0 to a different value
            do {
                p0++;
            } while (p0 + 3 <= p3 && num[p0] == num[p0 + 1]);
Which is wrong,     因为先加再对比,会出现这样的情况:例如,p1 =1,  num = [ -2, -1, 0 , 0 , 3]  运行完上面这句,  p1就变成 指向最后那个0 了
应该是
while (p1 < p2 && num[p1] == num[p1 + 1]){
                    p1++;
                };
                p1++;

9:这次写,没有update p3指针, 哎, 就是最右边的那个指针啦。
  还是像第一次那样,extract出一个子函数吧。 哎,~~~~丢人。 本以为很easy,可以一次pass的呢
10 : 第一遍的时候, p4=n-1 是在update p1之前。可是。这次,是在第一个while之后,因此,这样的话,每次要对比的,就是p0+3<n 的样子了。

-----------------------------第三遍--------------------------方法同上,  ----------
Mistakes:
1:  慎用 do {} while 语句。
例如, findMatch()中,要更新 i的位置(其实就是i2)
            do{
                i++;// avoid duplicates of j
            }while( i < j && num[i + 1] == num[i]) ;
这样是不对的。  因为,这样,首先更新了i的位置,再对比,就不再是 原有的i值的对比了。






No comments:

Post a Comment