[leetcode] 40. 组合总和 II

题目描述

给定一个候选人编号的集合 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

解题方法

dfs

这道题和第39题差不多,只是dfs写法略有区别,没看过的童鞋可以先看第39题

这道题候选数组包含了重复数字,相比39题dfs的解法有点区别:

  1. 每次dfs遍历时,若当前遍历数字与前一个数字相同,则当前dfs中包含该数字的有效集合都已遍历过,为了解集不包含重复的组合,需要跳过该数字。
  2. 当前参与计算的数字之和小于target时,继续dfs。因为每个数字不能重复使用,所以下一次的dfs起始位置为下一个数字。

java代码

public List<List<Integer>> combinationSum2(int[] candidates, int target) {
    List<List<Integer>> result = new ArrayList<>();
    Arrays.sort(candidates);
    List<Integer> curNums = new ArrayList<>();
    dfs(candidates, target, result, curNums, 0, 0);
    return result;
}

/**
 * @param candidates 从小到大排序后的候选数组
 * @param target     目标值
 * @param result     结果集集合,是个引用
 * @param curNums    当前参与计算的数字集合
 * @param curSum     当前参与计算的数字之和
 * @param start      dfs遍历数组开始的位置
 */
public void dfs(int[] candidates, int target, List<List<Integer>> result, List<Integer> curNums, int curSum, int start) {
    for (int i = start; i < candidates.length; i++) {
        // 如果当前数字与前一个数字相同,说明当前dfs中包含该数字的有效集合都已遍历过,不需要再次遍历
        if (i != start && candidates[i] == candidates[i - 1]) {
            continue;
        }
        // 当前参与计算的数字之和等于target,添加结果集,并跳出当前dfs
        if (curSum + candidates[i] == target) {
            curNums.add(candidates[i]);
            // 添加结果集的时候需要再new一个list,不然会添加引用,引用会不断变化。
            result.add(new ArrayList<>(curNums));
            curNums.remove(curNums.size() - 1);
            return;
        }
        // 当前参与计算的数字之和大于target,直接跳出当前dfs(因为数组都是正数,所以不会越加越小)
        if (curSum + candidates[i] > target) {
            return;
        }
        // 当前参与计算的数字之和小于target,继续dfs,不过下一次的dfs起始位置start为i+1
        curNums.add(candidates[i]);
        dfs(candidates, target, result, curNums, curSum + candidates[i], i + 1);
        curNums.remove(curNums.size() - 1);
    }
}

复杂度分析

时间复杂度: O ( 1 ) O(1) O(1)target最大为30,candidates数组中最小值是1,所以dfs最大深度为30,数组长度为100,30 * 100为常数级别。
空间复杂度: O ( 1 ) O(1) O(1),dfs最大深度为30,递归调用的存储空间是常数级别。

相似题目

[leetcode] 17. 电话号码的字母组合
[leetcode] 22. 括号生成
[leetcode] 37. 解数独
[leetcode] 38. 外观数列
[leetcode] 39. 组合总和


  • 个人公众号
    个人公众号
  • 个人小游戏
    个人小游戏
  • 12
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会飞的大鱼人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值