快捷搜索: 王者荣耀 脱发

LeetCode 之 n 个数之和(Sum n)

LeetCode 中有好几道题是求数字之和的,有 Sum 2、Sum 3 和 Sum 4 等。求和这种情况在我们实际开发中也是经常会遇到的,在这不妨拿出来我们把这归并到一起来说说。

无非就是数组中几个数字求和比较是否为目标值。且大多结果中是不能有重复的值。

大致我说下这个题意:

给定一个包含 m 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在 n 个元素,使得这 n 个元素相加的值与 target 相等?找出所有满足条件且不重复的组。

注意:
答案中不可以包含重复的组。

示例:
给定数组 nums = [1, 0, -1, 0, -2, 2], target = 0,n = 4

满足要求的四元组集合为:
[ [-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2] ]

两数之和好办,循环遍历去除重复结果。三数之和也类似。

那要是许多许多数之和呢,遍历就不好使了,那就要采用 BFS 或者 DFS。

答案中不可以包含重复的组从这我们知道,首先,我们需要将数组排个序。

由大化小的思想,我们可以采用 DFS + 回溯来解决这一系列问题。

苦恼不已,别挠头了,我们还是需要好好爱护自己的青青草地!

旨在锻炼逻辑思维,思想对了很重要,请上代码:

/**
     * 
     * @param nums
     *            排序后目标数组
     * @param target
     *            累加目标数值
     * @param k
     *            个数
     * @param index
     *            起始下标
     * @return
     */
    private ArrayList<List<Integer>> kSum(int[] nums, int target, int k, int index) {

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

        if (index >= len)
            return res;
        if (k == 2) { // 两数取和
            int i = index, j = len - 1;
            while (i < j) {
                // 满足条件塞入集合
                if (target - nums[i] == nums[j]) {
                    List<Integer> temp = new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[j]);
                    res.add(temp);
                    while (i < j && nums[i] == nums[i + 1]) // 跳过重复数值
                        i++;
                    while (i < j && nums[j] == nums[j - 1]) // 跳过重复数值
                        j--;
                    i++;
                    j--;
                } else if (target - nums[i] > nums[j])
                    i++;
                else
                    j--;
            }
        } else {
            for (int i = index; i < len - k + 1; i++) {
                // 调用递归 DFS
                ArrayList<List<Integer>> temp = kSum(nums, target - nums[i], k - 1, i + 1);
                // 若是有值返回则将该数塞入,无则不进行任何操作
                if (temp != null && temp.size() > 0) {
                    for (List<Integer> list : temp) {
                        list.add(nums[i]); // 将满足条件数值塞入
                    }
                    res.addAll(temp);
                }
                while (i < len - 1 && nums[i] == nums[i + 1]) // 跳过重复数值
                    i++;
            }
        }
        return res;
    }

注意:这里 len 定义的是个全局变量,初始值为 0

若 n 为 4,那程序应该是这样的:

int len = 0;
public List<List<Integer>> fourSum(int[] nums, int target) {
        len = nums.length;
        Arrays.sort(nums); // 先排序
        return kSum(nums, target, 4, 0); // 递归调用

    }

这下只要满足 n > 1 条件的都可以套用这个方法了。

要注意栈的深度。时间换空间。

经验分享 程序员 微信小程序 职场和发展