目录
题目链接:216.组合总和III
思路
与昨天的组合问题类似,只是这道题加了一个和的限制。代码框架就是回溯的经典框架,只是在处理节点和结果收集上有些改变。
代码
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking(int k, int n, int sum, int startindex) {
// 剪枝操作
if (sum > n) {
return; // 收集的数字之和已经大于目标值,直接返回
}
// 收集的数字已经达到了k个时进行结果收集
if (path.size() == k) {
// 如果数字之和sum与目标n相等,收集此时的结果
if (sum == n) {
result.push_back(path);
}
return;
}
// 节点处理
// for循环与集合宽度相关,1到9
// 剪枝操作:
// 从当前位置i到9共计还有9-i个数
// 剩下要收集的个数为 k - path.size个
// 如果剩下的数字个数已经不足以填满path,则不必再遍历
// 9-i >= k-path.size 才能保证填满path
// i <= 9 - (k-path.size) + 1
// 最后的加1是为了对齐下标
// 例如k=3,已经收集了2个数,i=9
// 9 <= 9 - (3-2); 9 <= 8?
// 9是最后一个可以收集的数,但是如果不加1,就收集不上
for (int i = startindex; i <= 9 - (k - path.size()) + 1; i++) {
sum += i;
path.push_back(i);
backtracking(k, n, sum, i + 1); // 递归
sum -= i; // 回溯
path.pop_back();
}
return;
}
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(k, n, 0, 1); // 初始sum为0,起始下标1
return result;
}
};
题目链接:17.电话号码的字母组合
思路
原先的思路是先处理数字字符串,将其转换成二维的字母字符串,但是做不下去了。看了题解,理解了映射的妙处,利用映射可以直接通过数字得到对应的字母字符串。
代码
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
};
vector<string> result;
string path;
void backtracking(string& digits, int index) {
if (index == digits.size()) {
result.push_back(path);
return;
}
// digits是字符串类型,里面的数字并转换成int型
int digit = digits[index] - '0';
string letter = letterMap[digit]; // 通过映射获取字母字符串
for (int i = 0; i < letter.size(); i++) {
path.push_back(letter[i]); // 收集字母
backtracking(digits, index + 1); // 递归
path.pop_back(); // 回溯
}
return;
}
vector<string> letterCombinations(string digits) {
if (digits.size() == 0)
return result; // 空集直接返回结果
backtracking(digits, 0);
return result;
}
};
总结
①加强了对回溯模板的理解
②映射的巧妙之处
③完成题目要求的功能后,继续思考剪枝的处理,提高效率