回溯-组合问题

什么是组合问题?

从N个数里面,选K个数,一共有多少种组合方式?

最基本的回溯,我们需要注意 1. 终止条件 2. for 循环横向 3. 回溯纵向 4. 剪枝
如果要将回溯的过程可视化的话,我会选择画一个树,
回溯的过程就是 dfs 这个树的过程。

image.png

继续拓展之、、、

选K个数,和为target?

回溯三件套+终止条件+排序剪枝

N个数中没有重复数字,可以使用不限次数,如何?

回溯三件套+回溯时(递归调用时)curIndex 不变+排序剪枝

N个数中有重复数字,每个限用一次,如何?

回溯三件套 + 去重 (※)+ 排序剪枝

回溯三件套

  1. 确定参数和返回值
  2. 确定终止条件
  3. 确定遍历过程

template 如下👍

function backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {// 同层
        处理节点;
        backtracking(路径,选择列表); // 递归进入下一层
        回溯,撤销处理结果 // 返回上一层
    }
}

所谓层,是指 遍历树 的层,比如我要从 5 个数abcde中选 3 个,
选第一个时,我可以有 5 种选择,a/b/c/d/e,相应的有 5 个分支,
那么,对于某一个分支,我需要继续选第二个数,比如 a,此时即递归调用backtracking函数,
选第二个时,我只有 4 种选择,b/c/d/e,......

练习题目:
77. 组合
216. 组合总和Ⅲ
...

剪枝优化

有哪些优化手段呢?什么时候需要优化呢?

  1. 剩余节点不够选的时候

k - path.length > n - curIndex + 1

  1. 当前节点总和已经大于target

去重

N个数中有重复数字,每个限用一次,如何?
对于这个问题,我们需要去重,
首先将数组排好序,例如 1 2 2 4 5 ,

按照之前的做法,试想一下,第一个数选 1,
第二个数可以为 2 / 2 / 4 / 5,需要删除第二个 选 2 的分支
下图说明了为什么需要删除
image.png

代码实例:
40. 组合总和Ⅱ

function backTracking(target,sum,curIndex,candidates){
    if(sum === target){
        result.push([...path]);
        return;
    }

    // 剪枝
    for(let i = curIndex; i < candidates.length && sum + candidates[i] <= target; i++ ){
        // 去重(巧妙🍎)
        if( i > curIndex && candidates[i] === candidates[i-1]){
            continue;
        }
        path.push(candidates[i]);
        sum += candidates[i];
        backTracking(target,sum,i + 1,candidates);
        path.pop();
        sum -= candidates[i];
    }
}
posted @   chuxin_jian  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示