216.组合总和|||
题目链接:216. 组合总和 III - 力扣(LeetCode)
解题思路:这题和组合问题有着很多相似的地方,基本的解题思路和代码格式也是大同小异只是略有区别,相当于这题是在组合问题上加上了一个条件,即k个元素的组合的和为n。同样使用回溯算法来解决。用两个全局数据来保存数据,分别是path和result,每遍历一个数则向path里面压入一个数,若符合题目要求的话,则将该path压入result,然后进行回溯操作。
1、函数返回类型和传入参数:因为要遍历所有情况,所以没有返回值,而传入的参数是(int n , int k , int sum , int startindex)其中n,k是题目所给定的数值,sum是求k个数的总和,而startindex用来记录起始索引位置,防止出现重复组合。
2、终止条件:当path.size() == k的时候则终止,然后判断此时的sum是否和n相等,若相等的话则用result保存此时的path。
3、单层递归逻辑:将遍历到的数值压入path,根据startindex的值来求本层递归中for循环中的sum,当path.size() == k时候判断sum是否和n相等,若相等则把当前path压入resul,然后进行回溯操作。
代码实现:
class Solution {
private:
vector<int>path;
vector<vector<int>>result;
void backtracing(int k ,int n ,int sum, int startindex){
if( path.size() == k){
if(sum == n){
result.push_back(path);
return;
}
}
for(int i = startindex; i < n;i++){
sum += i;
path.push_back(i);
backtracing(k, n, sum, i+1);
sum -= i;
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
result.clear();
path.clear();
backtracing(k,n,0,1);
return result;
}
};
以上是使用回溯算法进行全局搜索的代码,然而在很多种情况下我们不需要进行继续递归搜索,所以应该进行剪枝操作。
1、当sum>n的时候就不再继续进行搜索了,直接返回。
2、当从startindex开始向后遍历完所有的元素也不能满足达到k个元素的时候停止递归。
此时的i的范围应该是n - (k - path.size(()) +1;
代码实现:
class Solution {
private:
vector<int>path;
vector<vector<int>>result;
void backtracing(int k ,int n ,int sum, int startindex){
if(sum > n){ //剪枝
return ;
}
if( path.size() == k){
if(sum == n){
result.push_back(path);
return;
}
}
for(int i = startindex; i <= 9-(k - path.size() + 1);i++){//剪枝
sum += i;
path.push_back(i);
backtracing(k, n, sum, i+1);
sum -= i;
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
result.clear();
path.clear();
backtracing(k,n,0,1);
return result;
}
};
17.电话号码的字母组合
题目链接:17. 电话号码的字母组合 - 力扣(LeetCode)
解题思路:按照题目要求,我们首先应该建立起对应映射关系,即字符1对应“abc”这种映射关系,这里我们能够采用一个一维数组来进行映射,即索引是字符1,2,3....而里面的值是字符串。然后定义两个全局变量s和result用来收集结果,每遍历到一个字符则将这个字符压入s,若满足终止条件则将s压入result内,然后进行回溯。具体过程,建立映射关系,遍历输入的字符,将该字符单独存储为int型的数,用这个数来取对应的字符串,遍历该字符穿压入s内,若符合终止条件则使用result进行收集结果。
回溯三部曲:
1、递归函数返回类型和传入参数:遍历全局所以没有返回值,而传入参数是题目输入的字符和索引index,index用来记录此时遍历到哪个数字。
2、终止条件:当遍历到叶子节点即当index == digits.size()的时候进行收集结果。
3、单层递归逻辑:首先根据输入字符取出数,然后取出这个数对应的字符,然后使用for循环遍历这个字符,将遍历到的字符压入s内,进行下一层的递归,最后进行回溯。
代码实现:
class Solution {
private:
const string lettermap[10] = {
"",//0
"",//1
"abc",//2
"def",//3
"ghi",//4
"jkl",//5
"mno",//6
"pqrs",//7
"tuv",//8
"wxyz",//9
};
vector<string>result;
string s;
void backtracing(const string& digits ,int index){
if(index == digits.size()){
result.push_back(s);
return;
}
int digit = digits[index] - '0';//取数
string letters = lettermap[digit];//取字符
for(int i = 0; i< letters.size();i++){
s.push_back(letters[i]);
backtracing(digits,index+1);
s.pop_back();
}
}
public:
vector<string> letterCombinations(string digits) {
s.clear();
result.clear();
if(digits.size() == 0){
return result;
}
backtracing(digits ,0);
return result;
}
};