在数组中找出四个数字的和等于指定数字(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;
    }
}

实话讲,这个代码的时间复杂度还是有些高,如果字符串变态些还是怕扛不住……后面有好办法再跟新吧

    原文作者:K.Sun
    原文地址: https://blog.csdn.net/sinat_36246371/article/details/52806224
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞