回溯:组合总和

力扣39:组合总和
给定一个无重复元素的正整数数组 candidates 和一个正整数 target ,找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。
candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同,则两种组合是唯一的。
对于给定的输入,保证和为 target 的唯一组合数少于 150 个。
https://blog.csdn.net/qq_42999949/article/details/119713941?spm=1001.2014.3001.5501
在这里插入图片描述

做这道题之前,应该先做一下力扣77:组合
思路完全相同,只有一点改变。

本题思路:
首先定义一个结果数组,根据题意,res应是一个二维数组。由于我们递归需要参数startIndex(用来记录下一层递归,搜索的起始位置),所以在内部写一个递归搜索的函数search。
递归函数参数:
递归函数内包含三个参数,一个是startInedx,另一个是path用来存放符合条件结果,path是个一维数组,还有一个是sum,sum变量来统计单一结果path里的总和,其实这个sum也可以不用,用target做相应的减法就可以了,最后如果target==0就说明找到符合的结果了,但为了代码逻辑清晰,我依然用了sum。
在这里插入图片描述
递归的终止条件:
终止只有两种情况,sum大于target和sum等于target。sum等于target的时候,需要收集结果。
单层搜索的逻辑:
单层for循环依然是从startIndex开始,搜索candidates集合。
search(path,sum,i);
关键点:不用i+1了,表示可以重复读取当前的数!!

 function combinationSum(candidates, target) {
    let res=[];
    function search(path,sum,startIndex){
        if(sum>target) return;
        if(sum==target){
            res.push(path.slice());
        }
        for(let i=startIndex;i<candidates.length;i++){
            sum+=candidates[i];
            path.push(candidates[i]);
            search(path,sum,i);// 关键点:不用i+1了,表示可以重复读取当前的数
            sum-=candidates[i];// 回溯
            path.pop();// 回溯
        }
    }
    search([],0,0);//注意:这里startIndex的初始值是0,因为可以重复读取当前的值
    return res;
}

剪枝优化:

在这里插入图片描述
对于sum已经大于target的情况,其实是依然进入了下一层递归,只是下一层递归结束判断的时候,会判断sum > target的话就返回。其实如果已经知道下一层的sum会大于target,就没有必要进入下一层递归了。
剪枝:「对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历」。
for (let i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++)
并且需要对candidates数组进行排序
candidates=candidates.sort((a,b)=>a-b);

剪枝后的完整代码:

function combinationSum (candidates, target) {
    let res=[];
    candidates=candidates.sort((a,b)=>a-b);
    function search(path,sum,startIndex){
        if(sum>target) return;
        if(sum==target){
            res.push(path.slice());
        }
        for (let i = startIndex; i < candidates.length && sum + candidates[i] <= target; i++) {
            sum+=candidates[i];
            path.push(candidates[i]);
            search(path,sum,i);
            sum-=candidates[i];
            path.pop();
        }
    }
    search([],0,0);
    return res;
}

参考文章:https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值