216.组合总和III
解题思路
整体的思路和77题是一样的,这里只是多加了个一个和的判断。
剪枝操作也是一样的,首先剪深度,当和已经大于要求的和,那么就不需要继续深入了
第二个是剪宽度,当剩余的元素已经不能满足k个元素了,就不需要继续去拓宽搜索了
class Solution {
private:
vector<int> path;
vector<vector<int>> result;
public:
void backtracking(int k,int n, int startIndex)
{
if(n<0) return; //第一个剪枝,当小于0了,就必须要再继续深入了,因为已经不满足了,剪深度
if(path.size()>=k)
{
if(n==0)
{
result.push_back(path);
}
return;
}
for(int i = startIndex; i<= 9-(k-path.size())+1 ; i++) //第一个剪枝,剪宽度,和77题一样,还需要k个元素,那么i至多到9-k+1个
{
path.push_back(i);
backtracking(k,n-i,i+1);
path.pop_back();
}
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k,n,1);
return result;
}
};
- 时间复杂度: O(n * 2^n)
- 空间复杂度: O(n)
17.电话号码的字母组合
解题思路
这题比较关键的一个点是用二维数组来存储对应关系(这是我没有想到的)
这题回溯的深度,是由元素的个数决定的,这题的宽度,是由对应关系个数确定的。
其次就是注意逻辑的处理即可,详情见代码,本题也不需要剪枝,因为就是需要所有的可能性。
class Solution {
private:
vector<string> result; //记录结果
string s; //记录路径
const string letterMap[10] =
{
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz",
};
public:
void backtracking(const string& digits,int index) //这里的两个参数分别是题目给的字符串和 当前使用的字符串的下标
{
if(index == digits.size()) //当下标越界后就返回
{
//在此时收获结果
result.push_back(s);
return;
}
//取数字,这里使用字符相减即可
int digit = digits[index] - '0';
string letter = letterMap[digit];
for(int i =0;i<letter.size();i++)
{
s.push_back(letter[i]);
backtracking(digits,index+1); //深入去处理第二个数字
s.pop_back(); //回溯
}
}
vector<string> letterCombinations(string digits) {
if(digits == "") return result;
backtracking(digits,0);
return result;
}
};
小知识:string中取出单个的,是字符
const string& 是const引用传递,不会产生副本,也不会改变原来参数的值
&引用传递不会产生副本,直接会修改原来参数的值,传入的是地址
值传递,会产生副本,不会修改原来参数的值
收获
对于回溯里面的具体逻辑处理还是有点不太会,继续加油。