回溯算法总结

回溯算法

回溯算法概述

​ 回溯算法本质是一种穷举算法(可以通过剪枝来提高效率),回溯算法的模板是void ,参数,终止条件,for循环横向遍历,递归纵向遍历。回溯算法的题都可以抽象为树,求解的过程就是看每一个节点已取了什么,还剩下些什么。

组合问题

​ 77.组合:最经典也是最普通的回溯问题,因为是组合,所以横向遍历的时候不再取前面的数,纵向遍历的时候一个个取就行,如果个数不够k的话就剪枝。
​ 216.组合总和III:比起77那道题多了一个目标和,不过也就是在回溯到最下层的时候判断是否达到目标和了。
​ 17.电话号码的字母组合:这个题一是要解决映射,二是要解决多个集合间的组合问题。因为之前都是一个集合中的组合,多余这种多个集合中的组合,横向遍历就是直接遍历多个集合中的第一个集合中的元素,纵向遍历就遍历剩下的集合。
​ 39.组合总和:这题和216差不多,只是可以重复利用元素,所以递归的时候 i 不用加1了,然后这个剪枝还不是很容易想到,要先对数组排序,则如果当前这个元素的sum就大于target了,那for循环可以直接break掉。不过从LeetCode反馈来看,效率更低,应该是排序耗时较长。
​ 40.组合总和II:这题和39的区别在于数组里面的元素有重复的,且不能重复使用同一个元素。不重复使用同一个元素简单,递归的时候 i 加1就行;难点在于得到的结果不能有重复的,对于这种我们首先需要排序,然后分清树层去重和树枝去重的区别,树层去重是指前面已经讨论过的情况就不能再讨论了,树枝去重是指上一层选过的元素这一层不能再选,对于这一题树层去重即可。树层去重使用的方法是for循环的时候检查是否与前一个相同。

分割问题

​ 131.分割回文串:这道题首先要转化为回溯问题,其实就是回溯讨论切割位置的问题,而切割位置的判断我这里用的是一种左闭右闭的想法,最主要还是要想到怎么用回溯来切割,不过也感觉就是最基本的回溯的套路,至于判断回文倒是最简单的,还有,记得用substr函数。
​ 93.复原IP地址:其实这题和分割回文串差不多,主要这里要判断子串是否合法以及加入路径的时候要加一个点,只所以做了这么久,完全是因为把substr函数的参数含义搞错了,它的两个参数的含义是从某个位置开始拷贝多少个的字符。

子集问题

​ 78.子集:这题和前面的题不一样的地方在于前面的题都是求到叶子结点的结果,而这道题要求每一个节点的结果,不过也比较简单,就是在每一个节点都王result添加一个元素。
​ 90.子集II:还是和上面那道题差不多,只不过要先排序再加一个树层去重,还有就是递归的时候我又把 i 写成start了。

排列问题

​ 46.全排列:排列问题和组合问题的区别主要有两点,一是循环的时候排列是从0开始,二是每次循环都要判断当前元素是否在该路径已经使用过,即进行树枝去重。
​ 47.全排列II:这个很明显是要进行一个树层去重,但是千万注意,排列的树层去重和组合不一样。因为在排列中我们不能判断前一个元素是否位于同一层,所以要结合树枝去重的used数组进行树层去重,即前一个元素与当前元素相等且位于同一层才能去重。

棋盘问题

​ 51.N皇后:这个题回溯我觉得倒不是那么难,也是在横向进行for循环,纵向递归,我觉得比较难的点在于判断是否冲突,之前我的判断方式效率太低了,可以使用代码随想录的解法,即只判断上半部分的列和两个斜线方向的冲突。
​ 37.解数独:这个题和N皇后相似又有区别,相似的地方在于最重要的地方都是怎么判断棋盘上是否冲突,对于解数独,难的是判断九宫格中的冲突,这里一定要知道我们要从九宫格左上角那个位置开始判断,所以要想办法找到左上角那个位置,发现行和列除以3再乘以3即可。不同的地方在于之前做的题都是for循环一层,在一层中找到合适的,而这道题每一个位置都需要for循环,所以要注意位置的变化。

其他问题

​ 491.递增子序列:首先这题你要搞清楚子序列是什么,子序列不一定要是连续的,其次这题最主要的就是去重了,但是不能排序再树层去重,因为求子序列不能改变原序列,所以这里只能在每一层另设一个哈希表去重,另外,这题和子集类似,求的是每一个节点的结果。
​ 332.重新安排行程:这个题如果只是要通过样例的话不难,就是普通的回溯就行,难就难在有多条路径,如果你选择把多条路径全部弄出来比较的话会超时,所以要一开始搜索得到的就是最终路径,这就意味着要排序,即把一个机场能到的机场按字典序排序,这儿其实就已经决定要用一个unordered_map再加一个容器了,第二个容器要承担两个作用,即用过的机票不能再用和排序,所以我们再用一个map,然后再来回溯,反正又一点难这个题,需要再做几遍。

总结

​ 组合问题一般需要start作为标识(除了多个集合间的组合),排列问题不需要start,所以需要树枝去重,排列问题的树层去重尤其需要注意,因为其还需要判断是否处于同一层,分割问题就是对分割的位置进行回溯,棋盘问题也是对棋盘的选择进行回溯,比较重要的是判断是否冲突。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值