文章目录
- 0、 前言
- 1、回溯的定义
- 2、回溯解决那些问题
- 3、回溯模板
- 4、问题详解
- 4、1组合问题:
- [4.1.1 组合](https://leetcode.cn/problems/combinations/)
- [4.1.2 组合总和 II](https://leetcode.cn/problems/combination-sum-ii/)
- 4.1.3 组合的其他问题
- 4.2排列问题
- 4.2.1[全排列](https://programmercarl.com/0046.%E5%85%A8%E6%8E%92%E5%88%97.html)
- 4.2.2[全排列去重](https://programmercarl.com/0047.%E5%85%A8%E6%8E%92%E5%88%97II.html)
- 4.3子集问题
- 4.3.1子集
- 4.4 切割问题
- 分割回文串
- 4.5 棋盘问题
0、 前言
我很少写总结,但是回溯是我写的最多,个人也觉得比较重要的一个专题,所以写一个简单的总结一下这段时间刷的回溯题型
1、回溯的定义
回溯就是暴力搜索,而暴力确实我们在开发中最先想到一种方法,所以必须要掌握
2、回溯解决那些问题
- 组合问题: N个数里面按一定规则找出k个数的集合
- 排列问题: N个数按一定规则全排列,有几种排列方式
- 切割问题: 一个字符串按一定规则有几种切割方式
- 子集问题: 一个N个数的集合里有多少符合条件的子集
- 棋盘问题: N皇后,解数独等问题
3、回溯模板
回溯也是有套路的
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
4、问题详解
4、1组合问题:
4.1.1 组合
题目:
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案
总结:for循环横向遍历,递归纵向遍历,回溯不断调整结果集
4.1.2 组合总和 II
总结:我们在这里要学会组合问题的降重
在这里,我们要明白树枝去重和树层去重这两个概念
used[i-1] = true:表示的在同一个树枝上
used[i-1] = false:表示在同一个树层上
也可以用另外的一个方法if(i > index && nums[i] == nums[i-1]) continue
4.1.3 组合的其他问题
总结:
- 如果是一个集合来求组合的话,就需要startIndex,例如:回溯算法:求组合问题!
- 如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex,例如:回溯算法:电话号码的字母组合
4.2排列问题
排列问题和组合问题的区别:
- 每层都是从0开始搜索而不是startIndex
- 需要used数组记录path里都放了哪些元素了
4.2.1全排列
总结:这是模板题
4.2.2全排列去重
这道题有点意思,去重可以使用set,也可以使用used数组,但是基本上都是使用used,因为它的时间复杂度低一点
要好好判断是树枝降重和树层降重
4.3子集问题
4.3.1子集
总结:模板题
######4.3.2子集问题去重
总结:去重原理参照前面组合问题
4.4 切割问题
分割回文串
总结:
1、我们需要判断是否是回文串
2、组合的模板
3、我们需要判断切割的位置(要不要加i+1)
4.5 棋盘问题
暂时未总结,待更新