参考
题目一:LeetCode 216.组合总和III
会了昨天组合之后,这题就很简单了,除了用一个path保存路径外,再使用一个变量sum来保存路径的和。
- 确定递归函数的参数和返回值
参数:n,k,以及每次遍历的起始位置start.
返回值:无
void backtracking(int k,int n,int start);
- 确定递归终止条件:当path中元素个数等于k时,若路径值之和等于n,就将path保存到result中,然后结束递归
if(path.size() == k){
if(sum == n) result.push_back(path);
return;
}
- 确定单层搜索过程:for循环遍历树型结构的宽度,递归调用遍历深度,每次递归结束后进行回溯
for (int i = start; i <= 9; i++){
sum += i;
path.push_back(i);
backtracking(k,n,i+1);
sum -= i; //回溯
path.pop_back();
}
完整的代码实现如下:
class Solution {
public:
void backtracking(int k,int n,int start)
{
if(path.size() == k){
if(sum == n) result.push_back(path);
return;
}
for (int i = start; i <= 9; i++){
sum += i;
path.push_back(i);
backtracking(k,n,i+1);
sum -= i; //回溯
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k,n,1);
return result;
}
private:
vector<int> path;
int sum = 0;
vector<vector<int>> result;
};
剪枝
第一个地方和昨天的组合一样,对for循环的条件进行修改,当剩余元素不足所需要的元素个数时结束遍历,如下:
for (int i = start; i <= 10 - k + path.size(); i++){
......
}
第二个是当sum > n时直接退出:
if(sum > n) return;
剪枝后完整的代码如下:
class Solution {
public:
void backtracking(int k,int n,int start)
{
if(sum > n) return;
if(path.size() == k){
if(sum == n) result.push_back(path);
return;
}
for (int i = start; i <= 10 - k + path.size(); i++){
sum += i;
path.push_back(i);
backtracking(k,n,i+1);
sum -= i; //回溯
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k,n,1);
return result;
}
private:
vector<int> path;
int sum = 0;
vector<vector<int>> result;
};
题目二:LeetCode 17.电话号码的字母组合
字母和数字的映射
用一个string类型的数组来进行映射,如下:
string trans[8] = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
如果数字字符为ch,则其对应的字符串为trans[ch-‘2’],因为上面的数组中没有’0’和’1’对应的字符串,所以要减去偏移,当然也可以把’0’和’1’对应的字符串设置为空。
递归+for循环
用for循环来遍历每个数字对应的字符串,用递归来遍历每个数字。
- 确定递归函数的参数和返回值
参数:数字字符串digits,遍历每个数字字符的指针index
返回值:无
void backtracking(string digits,int index);
用path来保存遍历路径,result来保存最终的结果。
string path;
vector<string> result;
- 确定终止条件:当path保存的元素个数等于数字字符串的大小时,找到一个满足条件的答案,保存这个结果,然后结束本次递归。
if(path.size() == digits.size()){
result.push_back(path);
return;
}
- 确定单层搜索逻辑:用for循环来遍历每个字符对应的字母,用递归来遍历那个数字
string str = trans[digits[index]-'2']; //得到index指向的数字对应的字符
for(int i = 0;i < str.size(); i++){ //for循环遍历每个数字对应的字符
path += str[i]; //保存遍历结果
backtracking(digits,index+1); //递归遍历每个数字
path.erase(path.end()-1); //回溯
}
完整的代码实现如下:
class Solution {
public:
void backtracking(string digits,int index) //index遍历每个数字
{
if(path.size() == digits.size()){
result.push_back(path);
return;
}
string str = trans[digits[index]-'2']; //得到index指向的数字对应的字符
for(int i = 0;i < str.size(); i++){ //for循环遍历每个数字对应的字符
path += str[i]; //保存遍历结果
backtracking(digits,index+1); //递归遍历每个数字
path.erase(path.end()-1); //回溯
}
}
vector<string> letterCombinations(string digits) {
if(digits == "") return {};
backtracking(digits,0);
return result;
}
private:
string path;
vector<string> result;
string trans[8] = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
};