代码随想录算法学习心得 26 | 回溯法总结

一、回溯法总结

回溯是递归的副产品,只要有递归就会有回溯,所以回溯法也经常和二叉树遍历,深度优先搜索混在一起,因为这两种方式都是用了递归。

回溯法就是暴力搜索,并不是什么高效的算法,最多再剪枝一下,可以减少时间复杂度。

回溯算法能解决如下问题:

  • 组合问题:N个数里面按一定规则找出k个数的集合
  • 排列问题:N个数按一定规则全排列,有几种排列方式
  • 切割问题:一个字符串按一定规则有几种切割方式
  • 子集问题:一个N个数的集合里有多少符合条件的子集
  • 棋盘问题:N皇后,解数独等

回溯法确实不好理解,所以需要把回溯法抽象为一个图形来理解就容易多了,每一道回溯法的题目遍历过程都可以抽象为树形结构

1、对于组合问题,与直接用k层for循环相比较而言,回溯法的好处是可以用递归来控制for循环的嵌套数量。

 

 其搜索的过程:for循环横向遍历,递归纵向遍历,回溯不断调整结果集。对回溯法进行优化的方法是剪枝,剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了

2、对于组合总和(一),加了一个元素总和的限制。整体思路还是一样的,本题的剪枝会好想一些,即:已选元素总和如果已经大于n(题中要求的和)了,那么往后遍历就没有意义了,直接剪掉

3、对于组合总和(二)
与回溯算法:求组合总和的区别是:本题没有数量要求,可以无限重复,但是有总和的限制,所以间接的也是有个数的限制。
本题还需要startlndex来控制for循环的起始位置,对于组合问题,什么时候需要startlIndex呢
如果是一个集合来求组合的话,就需要startIndex,例如:回溯算法:求组合问题! ,回溯算法:求组合总和! 。
如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:回溯算法求电话号码
注意以上我只是说求组合的情况,如果是排列问题,又是另一套分析的套路。

4、对于组合总和(三),集合元素会有重复,但要求解集不能包含重复的组合。

去重的逻辑需要反复理解。

“树枝去重”和“树层去重”。组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上“使用过”,一个维度是同一树层上“使用过”。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。用一个used数组来进行标记。

5、对于多个集合求组合的问题

在回溯算法:电话号码的字母组合中,开始用多个集合来求组合,还是熟悉的模板题目,但是有一些细节。例如这里for循环,可不像是在回溯算法:求组合问题! 和回溯算法:求组合总和!中从startIndex开始遍历的。
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而回溯算法:求组合问题! 和回溯算法:求组合总和!都是是求同一个集合中的组合!

6、对于切割问题,切割回文串那道题目,难点在于以下方面:

  • 切割问题其实类似组合问题
  • 如何模拟那些切割线
  • 切割问题中递归如何终止
  • 在递归循环中如何截取子串
  • 如何判断回文

7、对于求子集的问题,在子集问题一中,在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果。在子集问题二中,需要对子集进行去重,逻辑与以前一样的,用一个used数组里进行标记。在递增子序列中,不能对原序列进行排序,也可以使用set针对同一父节点本层去重。

8、对于求排列的问题。排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了。

排列问题也要去重了,在回溯算法:排列问题(二)心中又一次强调了"树层去重"和”树枝去重”。

使用set去重的版本相对于used数组的版本效率都要低很多,主要是因为程序运行的时候对unordered_set频繁的insert,unordered_set需要做哈希映射(也就是把key通过hash function映射为唯一的哈希值)相对费时间,而且insert的时候其底层的符号表也要做相应的扩充,也是费时的。
而使用used数组在时间复杂度上几乎没有额外负担!,使用set去重,不仅时间复杂度高了,空间复杂度也高了,组合,子集,排列问题的空间复杂度都是O(n),但如果使用set去重,空间复杂度就变成了O(n^2),因为每一层递归都有一个set集合,系统栈空间是n,每一个空间都有set集合。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值