目录
前言
回溯理论基础
带你学透回溯算法(理论篇)| 回溯法精讲!_哔哩哔哩_bilibili
回溯算法的题目分类:
回溯算法的模板框架:
void backtracking(参数) {
if (终止条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
LeetCode77. 组合
LeetCode216.组合总和III
LeetCode17.电话号码的字母组合
一、LeetCode77. 组合
题目链接:
题目思路:
任何回溯的题目都可以看成是树的结构,如下图,这棵树就是通过[1, 2, 3, 4]这个集合得到的,从1开始向后取数,取过的数不再重复取。假设第一次取出的是1,也就是图中的从左往右的第一个结点,那么再往后就会产生三种情况,分别是[1, 2], [1, 3], [1, 4]。以此类推。假设我们用path变量记录每一个符合条件的结果,每次深入到下一层都相当于往变量path添加一个数,而每当我们往上一层走,就删除一个数。
代码:
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
void backtracing(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);
backtracing(n, k, i + 1);
path.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
backtracing(n, k, 1);
return result;
}
};
二、LeetCode216.组合总和III
题目链接:
题目思路:
题目思路与上一题大同小异,只不过需要回溯的结束条件和剪枝操作有所不同。
代码:
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
// 和要求为n,path的长度要求为k
void backtracting(int k, int n, int startIndex, int acc)
{
if(path.size() == k)
{
if(acc == n)
{
result.push_back(path);
}
return ;
}
for(int i = startIndex; acc + i <= n && i <= 9 - (k - path.size()) + 1; i++)
{
path.push_back(i);
backtracting(k, n, i + 1, acc + i);
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracting(k, n, 1, 0);
return result;
}
};
三、LeetCode17.电话号码的字母组合
题目链接:
题目思路:
对比前两题,这一题的一个最大的差别是每一层所需要回溯的数组是不同的,前两题都是对同一个数组进行操作,同时也设置了startIndex来记录下一层数组的起始位置(其实也可以看成是一个新的数组,数组的第一个元素在startIndex的位置)。但是本题中每一层用到的数组需要根据层数(index)和不同的digit来回溯不同的数组(letterMap)。
代码:
class Solution {
public:
const string letterMap[10] = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz", // 9
};
string s;
vector<string> result;
void backtracing(string& digits, int index)
{
if(index == digits.size())
{
result.push_back(s);
return ;
}
int letterIndex = digits[index] - '0';
string letter = letterMap[letterIndex];
for(int i = 0; i < letter.size(); i++)
{
s.push_back(letter[i]);
backtracing(digits, index + 1);
s.pop_back();
}
}
vector<string> letterCombinations(string digits) {
result.clear();
if(digits.size() == 0)
{
return result;
}
backtracing(digits, 0);
return result;
}
};