理论基础
回溯三部曲 ≈ 递归三部曲
回溯比递归多了一层对状态的记录,如path,该状态只记录当前,通过回撤来消除下一层的东西。
回溯本质是暴力搜索,复杂度没有变化,只能通过剪枝来减小一些复杂度。
cpp
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
77. 组合
有未知层for,for写不出来,所以用回溯,也就是递归。
递归的每一层for就是我们想写的每一层for,用if(终止条件)控制循环层数。
回溯算法通过递归的方式来控制for循环的层数。
grammar:
vector push_back() & pop_back();
cpp
class Solution {
public:
void backtracing(int n, int k, int start_index, vector<vector<int>>& res, vector<int>& path){
//终止条件
if(path.size()==k){
res.push_back(path);
return;
}
for(int i=start_index;i<=n-k+path.size()+1;i++){
path.push_back(i);
backtracing(n,k,i+1,res,path);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> result;
vector<int> path;
backtracing(n, k, 1, result, path);
return result;
}
};
216.组合总和III
跟77.组合问题不同的是:总和+[1,9]
剪枝不一定能剪掉每一个多余的枝。
剪枝1:if(sum>n)
剪枝2:i<=9-(k-(path.size()+1))和上一题一样
cpp
class Solution {
public:
void backtracing(int k, int n, int start_index, vector<vector<int>>& res, vector<int>& path, int sum){
if(sum>n){
return;
}
if(path.size()==k){
if(sum==n){
res.push_back(path);
}
return;
}
for(int i=start_index;i<=9-(k-(path.size()+1);i++){
path.push_back(i);
sum += i;
backtracing(k,n,i+1,res,path,sum);
sum -= i;
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> result;
vector<int> path;
backtracing(k,n,1,result,path,0);
return result;
}
};
17.电话号码的字母组合
其实完全可以两层for,不用回溯这么麻烦。
这是不同集合的组合,之前是同一集合的组合。
grammar:
cpp里string可以用push_back(), pop_back(),也可以直接+
list小写,用{}
map的key,value用,隔开
cpp
class Solution {
public:
map<char, list<char>> tele = {
{'2',{'a','b','c'}},
{'3',{'d','e','f'}},
{'4',{'g','h','i'}},
{'5',{'j','k','l'}},
{'6',{'m','n','o'}},
{'7',{'p','q','r','s'}},
{'8',{'t','u','v'}},
{'9',{'w','x','y','z'}}
};
void backtracing(vector<string>& res,vector<char>& path,vector<char>& digits, int start_index){
if(digits.size()==0){
return;
}
if(digits.size()==path.size()){
string s(path.begin(), path.end());
res.push_back(s);
return;
}
list<char> l = tele[digits[start_index]];
for(char c:l){
path.push_back(c);
backtracing(res, path, digits, start_index+1);
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string> result;
vector<char> path;
vector<char> v_digits(digits.begin(), digits.end());
backtracing(result, path, v_digits, 0);
return result;
}
};