回溯法模板
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
思路:首先确定函数的返回值和参数(一般是void,遇到回溯的时候考虑其他类型返回值)
vector<vector<int>> res;
vector<int> path;
void backtracking(int n,int k,int startindex){//startindex防止出现重复组合。
if(path.size()==k){
res.push_back(path);
return;
}
for (int i = startindex; i <= n;i++){
path.push_back(i);
backtracking(n, k, i + 1);
path.pop_back();
}
return;
}
vector<vector<int>> combine(int n, int k) {
backtracking(n, k, 1);
return res;
}
特殊情况:如下所示
图中每一个节点(图中为矩形),就代表本层的一个for循环,那么每一层的for循环从第二个数开始遍历的话,都没有意义,都是无效遍历。所以,可以剪枝的地方就在递归中每一层的for循环所选择的起始位置。如果for循环选择的起始位置之后的元素个数 已经不足我们需要的元素个数了,那么就没有必要搜索了。
void backtracking(int n, int k, int startindex)
{ // startindex防止出现重复组合。
if (path.size() == k)
{
res.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();
}
return;
}
// 所需要元素个数(k - path.size()) 列表中剩余元素n-i
// n-i+1>=k-path.size(),加1是为了包含i
// i<=n-(k-path.size())
2.216. 组合总和 III - 力扣(LeetCode)
思路:与上题类似,都是组合类问题。主要点就是递归与回溯。
vector<vector<int>> result;//存放结果集
vector<int> path;//存放符合条件的结果
void backtracking(int k, int n, int startindex) // n为和,k为个数
{
if (n < 0)//差值大于0;
return;
if(path.size() > k)//深度最多就是k,因为就取k个元素。
return;
if (path.size() == k && n == 0)
{
result.push_back(path);
return;
}
for (int i = startindex; i <= 10 - k + path.size(); i++)
{
path.push_back(i);
backtracking(k, n - i, i + 1);
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) // n为和,k为个数
{
backtracking(k, n, 1);
return result;
}
3.17. 电话号码的字母组合 - 力扣(LeetCode)
思路:注意这里for循环,可不像是在上面两个题中从startIndex开始遍历的。因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合 (opens new window)和216.组合总和III (opens new window)都是求同一个集合中的组合!
除此之外还要考虑到特殊情况,比如*或者#
string letters[10] = { // 数字和字母的映射
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz"};
vector<string> result;
string path; // 中间结果
void backtracking(string digits, int index) // index表示遍历到第几个数字
{
if (index == digits.size()) // 终止条件
{
result.push_back(path);
return;
}
int digit = digits[index] - '0';
for (int i = 0; i < letters[digit].size(); i++) // 遍历每个数字代表的字母们
{
path.push_back(letters[digit][i]);
backtracking(digits, index + 1);
path.pop_back();
}
}
vector<string> letterCombinations(string digits)
{
for (auto c : digits)
{
if (c == '*' || c == '#')
return result;
}
if (digits.empty())
return result;
backtracking(digits, 0);
return result;
}