【近日力扣】组合+子集 ||+组合总和

本文详细介绍了回溯算法的思想及其在组合、子集和组合总和问题中的应用。通过递归实现,强调了回溯过程中“回退步骤”的重要性,特别是在处理数组时需要适时删除元素以恢复原路径。同时,文章给出了代码示例,解释了如何避免子集中出现重复元素的方法,并探讨了一个递归细节,即何时需要进行拷贝操作以避免影响原始数据。
摘要由CSDN通过智能技术生成

回溯算法合集。要注意“回退步骤”,比如往数组里添加一个数,然后递归,则递归完要将该数再删除,才能实现原路径返回(回溯)

回溯是一种算法思想,可以用递归实现

组合(中等)

  • 思路:递归。维护一个子数组 path,首先存入一个数,作为开始数,后续存入的每一个数都做放入和不放入 path 的处理,找到所有的结果,每当 path 的长度等于 k 的时候就将 path 存入目标数组,然后再更改开始数,如此反复
var combine = function(n, k) {
    if (n < k) return []
    const res = [], path = []
    let dfs = (n, k, begin, path, res) => {
        if (path.length === k) {
            // push 参数如果是对象,则传入的是引用,必须转换(拷贝)一下
            res.push([...path]) // res.push(JSON.parse(JSON.stringify(path)))
            return
        }
        for (let i = begin; i <= n; i++) {
            path.push(i)
            dfs(n, k, i + 1, path, res)
            path.pop() // 回溯
        }
    }
    dfs(n, k, 1, path, res)
    return res
};

子集 II(中等)

  • 思路:递归。思路大致同上,通过回溯,找到每一种情况。难点是有重复数字时,如何给子集去重,详情见代码注释
var subsetsWithDup = function(nums) {
    if (!nums.length) return []
    nums.sort((a, b) => a - b)
    let res = [], path = []
    let dfs = (choose, cur, nums) => {
        if (cur === nums.length) {
            res.push([...path])
            return
        }
        // 如果不存入当前数
        dfs(false, cur + 1, nums)
        // 如果当前数等于上一位数,且上一位数未被选择,则返回,防止出现重复子集
        if (!choose && cur > 0 && nums[cur - 1] === nums[cur]) {
            return
        }
        path.push(nums[cur])
        // 如果存入当前数
        dfs(true, cur + 1, nums)
        path.pop() // 回溯
    }
    dfs(false, 0, nums)
    return res
};

组合总和(中等)

  • 思路:递归。思路了同上,代码有一处细节值得推敲
var combinationSum = function(candidates, target) {
    let res = []
    let dfs = (target, sub, idx) => {
        if (idx === candidates.length) return
        if (target === 0) {
            res.push(sub)
            return
        }
        dfs(target, sub, idx + 1)
        if (target - candidates[idx] >= 0) {
        	// 为何此处未做回溯的“回退”步骤?答案见代码底部
            dfs(target - candidates[idx], [...sub, candidates[idx]], idx)
        }
    }
    dfs(target, [], 0)
    return res
};
  • 因为此处是用扩展运算符对 sub 进行拷贝了,后续递归并没有直接改变 sub 的内容,所以当回溯到这一步时当前 sub 并未改变,不需要“回退步骤”

如果觉得对你有帮助的话,点个赞呗~

反正发文又不赚钱,交个朋友呗~

如需转载,请注明出处foolBirdd

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值