题目:4 Sum

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)

分析:根据之前解过的三数之和,这个问题很容易归纳为写个4重循环,时间复杂度O(n^4),但遗憾的是,无论在这个基础上怎么优化,它都会超时。

如果我们只需要求两数之和呢,需要写2重循环来枚举所有可能性吗?对于一个已排序的数组,这是没有必要的。我们需要做的只是,定义两个下标,一个在最左(设为left),一个在最右(设为right):

  • 如果num[left] + num[right] > target,那么应该当最右的下标左移,即right--
  • 如果num[left] + num[right] < target,则应该left++
  • 如果num[left] + num[right] == target,则这就是我们要找的组合了,同时left++,right--继续搜寻

上述算法时间复杂度O(n).

于是对于四数之和,我们便可能先甩出2重循环,确定前面两数,再对后面两个数采用上述算法搜索,总时间复杂度O(n^3).

代码:

public class Solution {
    public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
        ArrayList<ArrayList<Integer>> array = new ArrayList<ArrayList<Integer>>();
        ArrayList<Integer> solution = null;
        Arrays.sort(num);
        int left, right;
        int i, j , r;
        int len = num.length;
        if (len < 4) return array;

        for (i = 0; i < len - 3; i++) {
            if (i != 0 && num[i] == num[i-1]) continue;
            for (j = i + 1; j < len - 2; j++) {
                if (j != i + 1 && num[j] == num[j-1]) continue;
                left = j + 1;
                right = len - 1;

                while (left < right) {
                    if (left != j + 1 && num[left] == num[left-1]) {
                        left++;
                        continue;
                    }
                    if (right != len - 1 && num[right] == num[right+1]) {
                        right--;
                        continue;
                    }
                    r = num[i] + num[j] + num[left] + num[right];
                    if (r < target) left++;
                    if (r > target) right--;
                    if (r == target) {
                        solution = new ArrayList<Integer>();
                        solution.add(num[i]);
                        solution.add(num[j]);
                        solution.add(num[left]);
                        solution.add(num[right]);
                        array.add(solution);
                        left++;
                        right--;
                    }
                }
            }
        }
        return array;
    }
}

ssnau
1.5k 声望98 粉丝

负能量职业打码师


引用和评论

0 条评论