回溯法就是暴力搜索,并不是什么高效的算法,最多再剪枝一下。
回溯算法能解决如下问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 棋盘问题:N皇后,解数独等等
回溯不好理解,将回溯抽象为树的遍历后思路会更清晰一些
回溯模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
一.组合问题:
1.组合问题
对应LeedCode 77.组合
用递归来控制for循环嵌套的个数,收集所有的叶节点
剪枝精髓是:for循环在寻找起点的时候要有一个范围,如果这个起点到集合终止之间的元素已经不够题目要求的k个元素了,就没有必要搜索了。
2. 组合总和问题:
1)对应216.组合总和III
相当于在组合问题上加上和为n的限制,在递归函数参数多加两个值表示当前数相加的总和和目标总和
剪枝思路:已选元素总和如果已经大于n(题中要求的和)了,那么往后遍历就没有意义了,直接剪掉
2)对应LeedCode的39. 组合总和
Day 27 回溯法 LeedCode:39. 组合总和 40.组合总和II 131.分割回文串-CSDN博客
和上一题的组合总和题的区别在于本题的每个数可以无限制的取,所以递归参数index=i
3)
对应LeedCode40.组合总和II
Day 27 回溯法 LeedCode:39. 组合总和 40.组合总和II 131.分割回文串-CSDN博客
本题要求元素的每个数只取一次,集合元素会有重复,但要求解集不能包含重复的组合。
本题的特别之处在于如何去重,本题采用树层去重(同一父节点对应的子节点不能有相同的)
树层去重需要先将数组排序,让相对的挨着
if ( i > startIndex && candidates[i] == candidates[i - 1] )continue;
3.多集合求组合问题
对应LeedCode17.电话号码的字母组合,也就是求不同集合之间的组合
Day25:回溯法 LeedCode216.组合总和III 17.电话号码的字母组合-CSDN博客
二.切割问题
对应LeedCode131.分割回文串
Day 27 回溯法 LeedCode:39. 组合总和 40.组合总和II 131.分割回文串-CSDN博客
切割过的地方不能重复切割所以递归函数需要传入i + 1。
三.子集问题
在树形结构中子集问题是要收集所有节点的结果,而组合问题是收集叶子节点的结果。
Day28:回溯法 LeedCode 93.复原IP地址 78.子集 90.子集II-CSDN博客
1.对应78.子集问题
数组不包含重复的数
将找子集的回溯的过程抽象为遍历一棵树,那么结果集就是每个结点的集合
2.对应90.子集||
数组包含重复的数,要使得解集不包含重复子集,我们应该对树层去重,而不是树的路径去重
本题的去重:把数组排序,让重复的数排在一起,当前数等于前一数,就跳过当前数,注意第一个数没有前一个数
3.对应LeedCode491.递增子序列
Day29:回溯法 491.递增子序列 46.全排列 47.全排列 II-CSDN博客
本题和求子集相似,要求取有序子集,但子集不能重复,所以就不能将原数组排序后取子集实现去重,本题也是同一父节点下的同层上使用过的元素就不能再使用了
同一父节点下的同层上使用过的元素就不能再使用了,在for循环前定义set,递归前在set中查找本层是否已经用过该数,如果没用,将该数加入set,注意set只负责本层,所以进入下一层需要清空
四.排列问题
Day29:回溯法 491.递增子序列 46.全排列 47.全排列 II-CSDN博客
1.对应leedCode46.全排列
不含重复数字的数组
用回溯法收集叶节点,用uesd数组记录路径上哪些数字已经使用,实现路径去重,这里就不是树层去重了
2.对应LeedCode47.全排列II
含有重复数字的数组
本题与上一题区别在于,序列nums包含重复数字, 本题该如何去重呢?
先将数组排序,为了方便实现树层去重
-
used[i - 1] == true,说明同⼀树⽀nums[i - 1]使⽤过
-
used[i - 1] == false,说明同⼀树层nums[i - 1]使⽤过
-
如果同⼀树层nums[i - 1]使⽤过则直接跳过
if (i > 0 && nums[i] == nums[i - 1]&&used[i-1]==false ) {
continue;
}
五.棋盘问题
Day30 回溯 LeedCode 332.重新安排行程 51. N皇后 37. 解数独-CSDN博客
1.一维递归
对应leedCode51.N皇后问题]
n皇后问题一行只需要放一个皇后,for循环遍历列即可,递归函数参数传入行
2.二维递归
对应LeedCode37.独数解问题
一个for循环遍历棋盘的行,一个for循环遍历棋盘的列,一行一列确定下来之后,递归遍历这个位置放9个数字的可能性!