夯实算法-组合总和 II

100 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情

题目:LeetCode

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意: 解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

解题思路

由题意分析:利用回溯的方法大致思路是:

  • 遍历数组中的值,如果nums[i] < target , 尝试把nums[i]作为一个加数,把目标值减去nums[i],下一次递归从i+1开始遍历数组寻找下一个加数
  • 如果target=0,说明找到了一组加数
  • 否则把上一个加数从list中去掉

去重:需要先对数组进行排序,每次递归寻找的是一个位置的加数值,同一个位置不能使用相同的加数值

明确变化的状态

  • 从左到右开始选,每选一个数,我们都可以使用target - candidates[i]表示接下来还有凑出来的目标数
  • 选完后,下一个可以选择的数从i + 1开始
  • 保留选过的数。

代码实现

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

public List < List < Integer >> combinationSum2(int[] candidates, int target) {
    if (candidates.length == 0)
        return ans;
    Arrays.sort(candidates);
    helper(candidates, 0, target, new ArrayList < > ());

    return ans;
}

private void helper(int[] nums, int l, int target, List < Integer > list) {

    if (target == 0) {
        ans.add(new ArrayList < > (list)); //存入的是复制的list对象,避免递归时修改list也修改了ans中的解
        //list = new ArrayList<>();
        return;
    }
    for (int i = l; i < nums.length; i++) {
        //[10,1,2,7,6,1,5] => [1,1,2,5,6,7,10]  target=8
        //假设现在寻找第一个加数,nums[0] = 1 ,第一个加数是位置0的1,然后可以找到 [1,1,6] [1,7],最后递归回归到i=0,即寻找第一个加数的递归函数
        //尝试nums[1]作为第一个加数, 此时发现nums[1] = nums[0] ,那么递归下去一定可以找到重复的解[1,7], 因此跳过nums[1]
        // i > l的目的是 确保不是第一次使用这个加数,如果不保证i > l, 那么[1,1,6]这样的解就会丢失
        if (i > l && nums[i] == nums[i - 1])
            continue;
        if (target - nums[i] >= 0) {
            list.add(nums[i]);
            helper(nums, i + 1, target - nums[i], list);
            if (list.size() > 0)
                list.remove(list.size() - 1); //没有找到一组解
        }

    }
}

运行结果

Snipaste_2023-02-23_22-14-06.png

复杂度分析

  • 空间复杂度:O(1)O(1)
  • 时间复杂度:O(n)O(n)

掘金(JUEJIN)  一起分享知识, Keep Learning!