在数组中找出四个数字的和等于指定数字(4Sum)

112 篇文章 0 订阅
49 篇文章 3 订阅

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

好的,我可以回答这个问题。以下是使用Java语言编写的代码,可以找出数组nums中所有可以使数字和为target的组合: ```java import java.util.ArrayList; import java.util.List; public class CombinationSum { public List<List<Integer>> combinationSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList<>(); backtrack(result, new ArrayList<>(), nums, target, 0); return result; } private void backtrack(List<List<Integer>> result, List<Integer> tempList, int[] nums, int remain, int start) { if (remain < 0) { return; } else if (remain == 0) { result.add(new ArrayList<>(tempList)); } else { for (int i = start; i < nums.length; i++) { tempList.add(nums[i]); backtrack(result, tempList, nums, remain - nums[i], i); tempList.remove(tempList.size() - 1); } } } } ``` 这个代码使用回溯算法来找出所有的组合。我们首先定义一个空的结果列表result,然后调用backtrack方法来找出所有的组合。backtrack方法接受四个参数:result,tempList,nums和remain。tempList是一个临时列表,用于存储当前的组合。nums是给定的数组,remain是当前还需要凑出的数字和。start参数用于避免重复的组合。 在backtrack方法中,我们首先检查remain是否小于0,如果是,说明当前的组合不符合要求,直接返回。如果remain等于0,说明我们已经到了一个符合要求的组合,将其添加到结果列表中。否则,我们遍历数组nums,并将当前的数字添加到tempList中。然后,我们递归调用backtrack方法,将remain减去当前的数字nums[i],并将i作为start参数传递给下一次递归。递归完成后,我们将tempList中的最后一个数字删除,以便继续遍历数组。 最后,我们可以在主函数中调用combinationSum方法来找出所有的组合: ```java public static void main(String[] args) { int[] nums = {2, 3, 5}; int target = 8; CombinationSum solution = new CombinationSum(); List<List<Integer>> result = solution.combinationSum(nums, target); System.out.println(result); } ``` 输出结果为: ``` [[2, 2, 2, 2], [2, 3, 3], [3, 5]] ``` 这些组合分别是[2,2,2,2],[2,3,3]和[3,5],它们的数字和都为8。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值