今天学习了回溯的算法。
先记录一下模板:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
77. 组合 - 力扣(LeetCode) (leetcode-cn.com)
递归来做层叠嵌套(可以理解是开k层for循环),**每一次的递归中嵌套一个for循环,那么递归就可以用于解决多层嵌套循环的问题了**。
剪枝优化:
**所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置**。
**如果for循环选择的起始位置之后的元素个数 已经不足 我们需要的元素个数了,那么就没有必要搜索了**。
注意代码中i,就是for循环里选择的起始位置。
for (int i = startIndex; i <= n; i++) {接下来看一下优化过程如下:
已经选择的元素个数:path.size();
还需要的元素个数为: k - path.size();
在集合n中至多要从该起始位置 : n - (k - path.size()) + 1,开始遍历
为什么有个+1呢,因为包括起始位置,我们要是一个左闭的集合。
class Solution {
public:
vector> result;
vector 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(); // 回溯,撤销处理的节点
}
}
vector> combine(int n, int k) {
backtracking(n, k, 1);
return result;
}
};
46. 全排列 - 力扣(LeetCode) (leetcode-cn.com)
套模板解题
class Solution {
public:
vector>result;
vectorpath;
void backtracking(vector&nums,int k,vector&vistited){
if(path.size()==k)
{
result.push_back(path);
return;
}
int w=0;
for(int i=0;i> permute(vector& nums) {
vectorvistited(nums.size(),false);
backtracking(nums,nums.size(),vistited);
return result;
}
};
784. 字母大小写全排列 - 力扣(LeetCode) (leetcode-cn.com)
class Solution {
private:
vector result;
public:
void back(string &s, int i){
if(i==s.size()){
result.emplace_back(s);
return ;
}
if(isdigit(s[i])){
back(s, i+1);
}
else{
s[i]=tolower(s[i]);
back(s, i+1);
s[i]=toupper(s[i]);
back(s, i+1);
}
}
vector letterCasePermutation(string s) {
back(s, 0);
return result;
}
};



