1. 程式人生 > >在陣列中找出四個數字的和等於指定數字(4Sum)

在陣列中找出四個數字的和等於指定數字(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: 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]
]
理解題目很簡單,就是挑出所有四個數字的組合,這四個數字等於target就行,這個問題關鍵就是遍歷原始陣列……

說到遍歷,第一反應就是先把原陣列的四個數字的組個都拿出來,然後再看那個符合要求,但是這樣的做法估計在時間複雜度這關就過不了,就算出所有的組合就已經很費時間了。所以得另想辦法……

如果是三個數字的話,貌似簡單了許多,還有一點就是題目中沒有說我們不可以改變原始陣列,所以我們可以對這個陣列稍稍排個序,這又大大簡化了我們的問題,因為排序以後加和調整的方向是確定的,直接看程式碼吧,這樣容易理解一些。

三個數字:

public class ThreeSum {
    /**
     * @param nums
     * @return
     */
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list = new ArrayList<>();
        List<Integer> numsList = new ArrayList<>();
        for (int i = 0; i < nums.length; i++)
            numsList.add(nums[i]);
        Collections.sort(numsList);

        int len = numsList.size();

        for (int i = 0; i < len - 2; i++){
            if (i > 0 && numsList.get(i - 1).equals(numsList.get(i)))
                continue;
            Integer a = numsList.get(i);
            int low = i + 1;
            int high = len - 1;

            while (low < high){
                Integer b = numsList.get(low);
                Integer c = numsList.get(high);

                if ((a + b + c) == 0){
                    List<Integer> tl = new ArrayList<>();
                    tl.add(a);
                    tl.add(b);
                    tl.add(c);
                    list.add(tl);

                    while (low < len - 1 && numsList.get(low).equals(numsList.get(low + 1)))
                        low++;
                    while (high > 0 && numsList.get(high).equals(numsList.get(high - 1)))
                        high--;
                    low++;
                    high--;
                }else if ((a + b + c) > 0){
                    while (high > 0 && numsList.get(high).equals(numsList.get(high - 1)))
                        high--;
                    high--;
                }else{
                    while (low < len - 1 && numsList.get(low).equals(numsList.get(low + 1)))
                        low++;
                    low++;
                }
            }
        }
        return list;
    }
}

上面的實現還是比較好理解的,首先呢對陣列進行排序,排序的目的顯而易見,就是為了方便調整,三個數字分別為a,b,c。a就是從陣列開頭開始遍歷,b,c一個放在a的下一個位置,一個放在陣列的最後一個位置,如果當前三個傢伙的值跟target相等,那就啥也不說了了,直接新增,如果大於或者小於,那就得調整啦,具體咋調整程式碼寫的很清楚,這裡就不羅嗦啦……

那麼現在回頭再看這個問題,會發現無非就是在三個的基礎上再加一個數字變成四個,那行,還是上面的思路,無非就是兩層迴圈麼,程式碼相似度很大,於是有了下面的實現:

程式碼如下:

public class FourSum {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();

        List<Integer> integerList = new ArrayList<>();

        for (int num : nums) {
            integerList.add(num);
        }

        Collections.sort(integerList);

        int len = integerList.size();
        for (int i = 0; i < len - 3; i++) {
            if (i > 0 && integerList.get(i).equals(integerList.get(i - 1)))
                continue;
            Integer a = integerList.get(i);
            Integer rest = (Integer) target - a;

            for (int j = i + 1; j < len - 2; j++) {
                if (j > i + 1 && integerList.get(j - 1).equals(integerList.get(j)))
                    continue;
                Integer b = integerList.get(j);

                int low = j + 1;
                int high = len - 1;

                while (low < high) {
                    Integer c = integerList.get(low);
                    Integer d = integerList.get(high);
                    if (rest - (b + c + d) == 0) {
                        List<Integer> tl = new ArrayList<>();
                        tl.add(a);
                        tl.add(b);
                        tl.add(c);
                        tl.add(d);
                        result.add(tl);
                        while (low < len - 1 && integerList.get(low).equals(integerList.get(low + 1)))
                            low++;
                        while (high > j + 1 && integerList.get(high).equals(integerList.get(high - 1)))
                            high--;
                        low++;
                        high--;
                    } else if (rest - (b + c + d) > 0) {
                        while (low < len - 1 && integerList.get(low).equals(integerList.get(low + 1)))
                            low++;
                        low++;
                    } else {
                        while (high > j + 1 && integerList.get(high).equals(integerList.get(high - 1)))
                            high--;
                        high--;
                    }
                }

            }

        }
        return result;
    }
}
實話講,這個程式碼的時間複雜度還是有些高,如果字串變態些還是怕扛不住……後面有好辦法再跟新吧