【LeetCode】40. 组合总和 II(中等)——代码随想录算法训练营Day27

题目链接: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

文章讲解:代码随想录

视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili

题解1:回溯法

思路:使用回溯法来求解组合问题。

回溯分析:

  • 递归函数的参数和返回值:首先创建2个变量 res、path,path 记录遍历的路径,res 记录结果。递归函数的返回值为 void,参数是 start 和 sum,start 记录本次递归的开始位置,sum 记录当前路径和。
  • 递归函数的终止条件:找到叶子节点,即路径和等于目标值,也就是找到了一个符合题目要求的组合,将这个组合存入结果数组。当路径和大于目标值时,返回。
  • 单层递归的逻辑:使用 for 循环从开始位置 start 开始直到数组末尾进行横向遍历,递归的向下纵向遍历寻找组合。
  • 剪枝:先对原数组进行排序,在遍历过程中,如果 sum 加上当前元素后大于 target 了,说明本层后面的结果都会大于 target,就没必要往后遍历了。
  • 去重:树层去重,树枝不去重。
/**
 * @param {number[]} candidates
 * @param {number} target
 * @return {number[][]}
 */
var combinationSum2 = function(candidates, target) {
    candidates.sort((a, b) => a - b); // 对原数组进行排序
    console.log(candidates);
    const res = [];
    const path = [];
    const backtracking = function (start, sum) {
        if (sum === target) {
            res.push([...path]);
            return;
        }
        if (sum > target) {
            return;
        }
        for (let i = start; i < candidates.length; i++) {
            if (i > start && candidates[i] === candidates[i - 1]) {
                continue; // 去重,当前数组元素和上一个元素相同时,跳过本次循环
            }
            if (sum + candidates[i] > target) {
                return; // 剪枝
            }
            path.push(candidates[i]);
            backtracking(i + 1, sum + candidates[i]); // 向下查找
            path.pop(); // 回溯
        }
    }
    backtracking(0, 0);
    return res;
};

分析:时间复杂度为 O(n * 2 ^ n),空间复杂度为 O(n)。

收获

练习使用回溯法求解组合类问题,去重方法和数组中去重一样,要注意树枝去重和树层去重。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晴雪月乔

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

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

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

打赏作者

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

抵扣说明:

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

余额充值