对于回溯算法,我对于他的本质理解为穷举,当然,并不否认在过程中可以剪枝,使得时间复杂度下降,但是究其本质还是去考虑所有的情况
基本的格式如下(接下来的代码学习也会按照这个格式来写,从而不断加深印象)
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
例题1 . - 力扣(LeetCode)
//三部曲去考虑,边界条件,返回值与传递参数, 循环过程
//当然这其中把temp去作为一个参数也是可以的,但是会占用很多的栈空间,想要去试试的也可以自己写一写
class Solution {
private:
vector<vector<int>> ans;
vector<int> temp;
void backtracking(int m, int n, int k){
if(temp.size() == k){
//边界条件
ans.push_back(temp);
return;
}
for(int i = m; i <= n; i++){
temp.push_back(i);
backtracking(i + 1, n, k);
temp.pop_back();
}
}
public:
vector<vector<int>> combine(int n, int k) {
backtracking(1, n, k);
return ans;
}
};
剪枝优化在当中也被提及,可能在代码随想录的一开始描述的有一些模糊,我们用这个例子就可以了,n = 4,k = 4的情况,第一层的回溯按照原来的情况是1-4的循环,但是我们很清楚,只有一个可能性,那就是[1, 2, 3, 4]。所以i的限制条件可以变成 i <= n - (k - temp.size()) + 1。这样的话第一层就是4 - ( 4 - 0 ) + 1 = 1-------i <= 1就可以了。
例题2.. - 力扣(LeetCode)
//和第一题大差不差,把第一题提到的vector作为参数了。当然写起来也麻烦了许多
class Solution {
private:
vector<vector<int>> ans;
void backtracking(int k, int n, int start, vector<int> temp, int sum){
if(sum == n && temp.size() == k) {
ans.push_back(temp);
return;
}
if(sum >= n || temp.size() >= k) return;
for(int i = start; i < 10 && i <= n - sum + 1; i++){
temp.push_back(i);
backtracking(k, n, i + 1, temp, sum + i);
temp.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k, n, 1, {}, 0);
return ans;
}
};
例题3.. - 力扣(LeetCode)
class Solution {
//本质与例题1相似
private:
vector<string> ans;
vector<string> strs = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
string s;
void backtracking(string digits, int start){
if(start == digits.length()){
ans.push_back(s);
return;
}
int num = digits[start] - '2';
for(int i = 0; i < strs[num].length(); i++){
s += strs[num][i];
backtracking(digits, start + 1);
s.pop_back();
}
}
public:
vector<string> letterCombinations(string digits) {
if(digits == "") return ans;
backtracking(digits, 0);
return ans;
}
};
例题4.. - 力扣(LeetCode)
class Solution {
private:
vector<vector<int>> ans;
vector<int> path;
void backtracking(vector<int> candidates, int target, int start){
if(target == 0){
ans.push_back(path);
return;
}
if(target < 0) return;
for(int i = start; i < candidates.size(); i++){
path.push_back(candidates[i]);
backtracking(candidates, target - candidates[i], i);
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates, target, 0);
return ans;
}
};
代码随想录网址:代码随想录