代码随想录-回溯法
做题模板
做递归题目的时候,可按照下面的模板。
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中的元素) {
处理节点;
backtracking(路径,选择列表);
回溯,撤销处理结果;
}
}
回溯法能够解决如下问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 排列问题:N个数按一定规则全排列,有几种排列组合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 棋盘问题:N皇后,解数独等等。
题目分类总结
组合问题
用递归控制for循环嵌套的数量。
回溯问题的搜索过程:for循环横向遍历,递归纵向遍历,回溯不断调整结果集。
- 给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
常规操作。可以采取的剪枝优化方法就是i不小于n,而是i < n - (k - path.size())。比如n = 4, k = 4的时候,for循环的时候从元素2开始遍历就没有意义了。 - 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
和上一道题一样,不同的就是有1个相加和的限制。 - 电话号码的数字组合:这道题需要提前把数字和字母的映射存在一个数组里面,然后再用回溯的方法去做。
4.leetcode39 组合总和:这道题目中的数组元素不重复。与上面题目不同的是这个题目可以重复选取数组中的元素,所以在进行递归的时候,startIndex不用加1。 - leetcode40 组合总合ii:这道题目中的数组元素是可以重复的,但是数组candidates中的每个元素只能使用一次。具体做法就是:先把数组给排下序,然后让相同的元素可以挨在一起。题目要求不能包含重复的组合。我们要想办法进行去重。我们要进行树层的去重而不是树枝的去重。用used数组来表示这个元素是否被使用过。所以在递归函数中的循环中,要加上如下的代码:
if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] = 0) {
return;
}
用这种方法进行去重。
分割问题
- leetcode 131 分割回文串:和组合问题类似。需要在循环中判断一下截取到的这个字符串是不是回文串。判断回文串的方法:1)用两个指针,一个指着头,一个指着尾,然后进行比较,看是否都相等来判断是否是回文字符串。2)把字符串进行反转,然后对原始的字符串和翻转后的字符串进行比较来判断。
- leetcode 93 复原IP地址:与上一个分割问题类似,这道题目就需要判断截取的字符串是否是有效的IP地址。
子集问题
- leetcode 78 子集:这道题需要把对应的树形结构的元素全部加入最终结果中,所以递归函数中就是不用判断条件的把path加入到result中。
- leetcode 90 子集II:题目中的整数数组可能包含重复元素的整数数组,但是解集中不能包含重复的子集。这道题的解法就是leetcode 78加上树层去重。
- leetcode 491 递增子序列:这道题目要要求去重,但是不能对题目中的整数数组进行排序,所以不能用之前用的去重方法。所以就需要在对应的树形结构的每一层加一个HashSet类型的变量。这样就可以判断这一层是否已经加入过相同的元素来进行去重。
排列问题
- leetcode 46 全排列:和上面问题的解决思路类似,不同的就是需要加入一个used数组,来去看看这个元素有没有被使用过。
- leetcode 47 全排列II:在上一个题的基础上,加上树层去重。
重新安排行程
- leetcode 332 重新安排行程:这道题有几个点需要注意:
- 如果处理不好一个往返行程的机票,容易造成死循环的状况。
- 如果保证在有多种解法的时候,字母排序较小的排在前面呢?
- 递归的终止条件是什么?
对应的解决办法为: - 用used数组来记录这张机票是否使用过;
- 在解决这个题之前,根据数组里面每一张机票的到达地对数组进行排序
Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
- 递归的终止条件:
弄清楚这些问题,这道题就比较容易解决了。因为这道题要求返回一个符合条件的结果就可以了,所以递归函数的返回类型是boolean。path.size() == ticket.size() + 1;
棋盘问题
- leetcode 51 N皇后:在这个题目中要明确棋盘的宽度是for循环的长度,递归的深度是棋盘的高度。除此之外,要写一个在棋盘的这个位置放这个皇后是否有效的函数,即检查这一列和两条对角线上是否有皇后。
- leetcode 37 解数独:这个题目没有终止条件,在递归函数中遍历行、遍历列、遍历要放的字符来进行处理。