回溯的理论基础
其实在讲解二叉树的时候,就给大家介绍过回溯,这次正式开启回溯算法,大家可以先看视频,对回溯算法有一个整体的了解。
题目链接/文章讲解
视频讲解
回溯的总结:
树的深度(递归的层数)
树的深度就是要取的数据的个数,通过path的size判断是否收集到足够的数据
树的宽度(循环的范围)
输的宽度就是搜索的范围,就是for循环的循环范围,这个范围可以做剪枝操作
递归和回溯就是在这颗树上做搜索,深度优先
回溯的函数
退出条件:
收集到足够的数据,也就是到达了指定的深度
递归
每一个递归就是给一个范围获取一个数字,递归的获取数字,到了指定的数量(深度)结束递归
循环
进入下一个循环的时候需要回溯,将上一个递归获取的数据pop掉,用来接收下一个数据
剪枝
1 对循环的范围做剪枝
2 根据对数据的要求做做剪枝
回溯函数的模板
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}
组合
leetcode题目链接
题目链接/文章讲解
视频讲解
剪枝操作
//未剪枝
class Solution {
private:vector<vector<int>> result; // 存放符合条件结果的集合vector<int> 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(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {result.clear(); // 可以不写path.clear(); // 可以不写backtracking(n, k, 1);return result;}
};//剪枝操作,代码优化
class Solution {
private:vector<vector<int>> result; // 存放符合条件结果的集合vector<int> 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(); // 回溯,撤销处理的节点}}
public:vector<vector<int>> combine(int n, int k) {result.clear(); // 可以不写path.clear(); // 可以不写backtracking(n, k, 1);return result;}
};