力扣216、组合总和III
思路:组合总和和上一道题组合有着很多相似的地方,比如说,它们都要求是k个数的组合,再比如它们都是在一个给定的范围内选取元素,只不过这道题目多了一个总和的限制,这一点可以通过增设参数来解决。
首先我们需要定义一个结果集,还需要定义一个二维数组用来保存结果集,接着我们需要确定回溯函数的返回值及参数,返回值我们说过了,没有特殊情况都是void,至于参数,题目所要求的总和肯定要有吧,我给他命名为targetSum,其次还需要k用来表示组合的个数要求,范围是给定的,此外为了方便比较当前结果集中的总和和目标值的差距,我们设置一个sum表示当前和,再设置一个index用来记录下一次使用搜索开始的位置。
接下来我们要做的就是确定终止条件了,一般情况下,当我们把回溯问题转换成N叉树后,当我们碰到叶子节点时,就是递归的终止了,在这里就是当我们结果集中的元素个数已经等于组合个数的要求k时,就去比较结果集中的sum和目标值的差距,如果二者相等,我们就保存结果到二维数组中,否则直接return
最后就是单层递归的逻辑了,我们用for循环来进行横向遍历,用递归来进行纵向遍历,for循环来遍历给定的范围,也就构成了树的宽度,递归的深度则由k决定,递归后要通过回溯来撤销之前运行的痕迹,这样代码的逻辑大致就写完了。
代码:
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
//targetSum是目标和
//sum是已经球的的和
//startIndex记录下层遍历开始的搜索位置
void backtracking(int targetSum,int k,int sum,int startIndex){
if(path.size()==k){
if(sum==targetSum)result.push_back(path);
return;
}
for(int i=startIndex;i<=9;i++){
sum+=i;
path.push_back(i);
backtracking(targetSum, k, sum, i+1);//i+1调整下层搜索的起始位置
sum-=i;
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
result.clear();
path.clear();
backtracking(n, k, 0, 1);
return result;
}
};
17、电话号码的字母组合
思路:本题同样是一道组合类型的问题,但是和上一题不同,对于本题而言,结果集的长度由输入的字符串的长度决定,结果集的每一位字符由字符串对应位置的字符所对应的数字确定。
首先还是要先定义两个全局变量,一个定义成字符串用来保存符合条件的字母组合,一个定义成字符串数组用来保存所有符合条件的字母组合。然后就是回溯第一步了,返回值还是void,参数的话题目所给的字符串我们肯定需要呀,为了保证安全,我们可以给它加上一个const,接着我们还要再添加一个int型变量index,用来告诉我们下一次搜索的字符位置。
接着就是递归的中止条件,把本题转化成N叉树,那么当我们碰到叶子节点的时候,也就是我们的字符串的大小和输入的字符串的大小长度相同的时候,我们就保存结果,return即可。(这里用index做判断也可以)
最后是单层递归逻辑,我们用for循环来把当前数字所对应的字符集给加入字符串,用递归来实现长度符合题目要求的结果集字符串,用回溯来撤销之前的痕迹重新递归。
补充说明:这里应该如何处理一个数字所对应的字母集呢?我们可以定义一个二维数组来实现。
代码:
class Solution {
public:
vector<string>result;
string s;
//定义一个二维数组用来保存字符集
const string stringMap[10]={
"",//0
"",//1
"abc",//2
"def",//3
"ghi",//4
"jkl",//5
"mno",//6
"pqrs",//7
"tuv",//8
"wxyz",//9
};
void backtracking(const string&digits,int startIndex){
//注意这里的startindex和组合里面的作用不同,这里的startindex是用来记录下一个要处理的数字
//字符串的长度决定了树的深度,每一个字符所对应的键盘上的数字决定了树的宽度
if(s.size()==digits.size()){
result.push_back(s);
return;
}
int digit=digits[startIndex]-'0';//将startindex转换成整型
string stringLetter=stringMap[digit];
for(int i=0;i<stringLetter.size();i++){//这里第二个循环条件很细节,i小于字符集的长度
s.push_back(stringLetter[i]);
backtracking(digits, startIndex+1);//递归
s.pop_back();//回溯
}
}
vector<string> letterCombinations(string digits) {
result.clear();
s.clear();
if(digits.size()==0){
return result;
}
backtracking(digits, 0);
return result;
}
};