自助服务系统网站,建设监理网站,网站的建设与颜色搭配,wordpress改变访问目录目录#xff1a;
解题及思路学习
理论基础
回溯的本质是穷举#xff0c;穷举所有可能#xff0c;然后选出我们想要的答案#xff0c;如果想让回溯法高效一些#xff0c;可以加一些剪枝的操作#xff0c;但也改不了回溯法就是穷举的本质。
回溯法#xff0c;一般可以…目录
解题及思路学习
理论基础
回溯的本质是穷举穷举所有可能然后选出我们想要的答案如果想让回溯法高效一些可以加一些剪枝的操作但也改不了回溯法就是穷举的本质。
回溯法一般可以解决如下几种问题
组合问题N个数里面按一定规则找出k个数的集合切割问题一个字符串按一定规则有几种切割方式子集问题一个N个数的集合里有多少符合条件的子集排列问题N个数按一定规则全排列有几种排列方式棋盘问题N皇后解数独等等
组合是不强调元素顺序的排列是强调元素顺序。
**回溯法解决的问题都可以抽象为树形结构。**因为回溯法解决的都是在集合中递归查找子集集合的大小就构成了树的宽度递归的深度都构成的树的深度。
递归就要有终止条件所以必然是一棵高度有限的树N叉树。
回溯法模板 回溯函数模板返回值以及参数 在回溯算法中我的习惯是函数起名字为backtracking这个起名大家随意。 回溯算法中函数返回值一般为void。 再来看一下参数因为回溯算法需要的参数可不像二叉树递归的时候那么容易一次性确定下来所以一般是先写逻辑然后需要什么参数就填什么参数。
void backtracking(参数)• 回溯函数终止条件
什么时候达到了终止条件树中就可以看出一般来说搜到叶子节点了也就找到了满足条件的一条答案把这个答案存放起来并结束本层递归。
if (终止条件) {存放结果;return;
}• 回溯搜索的遍历过程
在上面我们提到了回溯法一般是在集合中递归搜索集合的大小构成了树的宽度递归的深度构成的树的深度。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xv8cyb7n-1692784851158)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/604286bd-c456-4ea9-abcc-f9818b86e905/Untitled.png)]
for (选择本层集合中元素树中节点孩子的数量就是集合的大小) {处理节点;backtracking(路径选择列表); // 递归回溯撤销处理结果
}for循环就是遍历集合区间可以理解一个节点有多少个孩子这个for循环就执行多少次。
backtracking这里自己调用自己实现递归。
大家可以从图中看出for循环可以理解是横向遍历backtracking递归就是纵向遍历这样就把这棵树全遍历完了一般来说搜索叶子节点就是找的其中一个结果了。
总的模板
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择本层集合中元素树中节点孩子的数量就是集合的大小) {处理节点;backtracking(路径选择列表); // 递归回溯撤销处理结果}
}回溯相当于递归里面还嵌套着for循环。
77. 组合
给定两个整数 n 和 k返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1
输入n 4, k 2
输出
[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],
]思考组合是无序的。
class Solution {
public:vectorvectorint result;vectorint path;void backtracking(int n, int k, int startIndex) {if (path.size() k) {result.push_back(path);return;}for (int i startIndex; i n; i) {path.push_back(i);backtracking(n, k, i 1);path.pop_back();}}vectorvectorint combine(int n, int k) {backtracking(n, k, 1);return result;}
};时间复杂度: O(n * 2^n)空间复杂度: O(n)
剪枝操作
这个操作一般是在for循环部分进行。缩小搜索的范围。
可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。
如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了那么就没有必要搜索了。
class Solution {
public:vectorvectorint result;vectorint path;void backtracking(int n, int k, int startIndex) {if (path.size() k) {result.push_back(path);return;}for (int i startIndex; i (n - (k - path.size()) 1); i) {path.push_back(i);backtracking(n, k, i 1);path.pop_back();}}vectorvectorint combine(int n, int k) {backtracking(n, k, 1);return result;}
};复盘总结
个人反思
今日学到了
1、回溯三部曲。
确定返回值及参数确定终止条件确定单层的遍历过程
2、for循环里面相当于是宽度for循环里面的回溯相当于是深度。
3、剪枝操作一般都是在for循环那里(n - (k - path.size()) 1) 。即选择搜索的极限位置。