【JS每日一算法】34.组合总数Ⅱ(深度优先+剪枝)

4,326 阅读2分钟

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

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

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

示例:

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

更多JS版本题解点击链接关注该仓库👀

/**
 * @description: 深度遍历+剪枝   TC:O(2^n)  SC:O(n)
 * @author: JunLiangWang
 * @param {*} candidates  给定数组
 * @param {*} target      给定目标值
 * @return {*}
 */
function dfs(candidates,target)
{
    /**
     * 该题采用深度优先+剪枝的方法,它与上一题"组合总和Ⅰ"非常相似,但多加了一个
     * 条件:每个数字不再可以无限制重复被选取,只能使用一次;因此我们对上一个算法
     * 进行改进即可:
     * 1.将递归中跳转到下一个元素变为跳转到下一个不重复的元素
     *    recursion(targetValue,combineed,index+1) => 
     *    recursion(targetValue,combined,notRepeatingIndex);
     * 2.将递归中减去当前值,继续递归本次元素变为继续递归下一个元素
     *    recursion(diff,[...combined,candidates[index]],index) => 
     *    recursion(diff,[...combined,candidates[index],index+1])
     */

    // 对数组进行排序,方便后续去重、剪枝处理
    candidates.sort((a,b)=>a-b);
    // 定义输出数组
    let outArray=[];
    /**
     * @description: 递归遍历,表示当前在candidates数组的第
     *               index位,还剩targetValue要组合
     * @author: JunLiangWang
     * @param {*} targetValue  当前目标值
     * @param {*} combined     已组合的值
     * @param {*} index        当前candidates索引
     * @return {*}
     */    
    function recursion(targetValue,combined,index){ 
        // 如果targetValue等于零,证明当前组合的和
        // 为target,将当前组合(combined)加入输出数组
        if(targetValue===0)
        {
            outArray.push(combined);
            return ;
        }
        // 如果当前索引超出了给定数组范围,直接return
        if(index>=candidates.length)return ;
        // 初始化与当前元素不重复的后一个元素的索引为当前元素+1
        let notRepeatingIndex=index+1;
        // 找到与当前元素不重复的后一个元素的索引,由于candidates
        // 为升序,因此仅需要找到与当前元素不同的元素,即可跳过全部
        // 相同的元素
        while(candidates[notRepeatingIndex]==candidates[index])notRepeatingIndex++;
        // 如果当前目标值减去差值小于0,由于candidates为升序
        // 因此后续元素与当前差值依旧会小于0,因此舍去(剪枝)
        // 如果大于等于0则继续递归
        let diff=targetValue-candidates[index];
        if(diff>=0)
        {
            // 跳到不重复的元素继续递归
            recursion(targetValue,combined,notRepeatingIndex);
            // 减去当前值,继续递归下一个元素
            recursion(diff,[...combined,candidates[index]],index+1);
        }
    }
    // 执行递归
    recursion(target,[],0)
    // 输出结果
    return outArray;
}

来源:力扣(LeetCode)