链接:216. 组合总和 III
思路:
这道题目与77. 组合仅有一点不同,就是这道题目找到的组合的总和需要满足额外的条件。所以在递归终止条件里增加了一个条件就是当sum==n的时候才把答案push进最终结果里。除此之外,还有一点区别就是这里的n不再是作为搜索范围而存在的,而是以target而存在的,题目里提到了每一个数都可以从1到9里面选择,所以搜索范围就变成了i <=9,并且这里也用上了和之前一样的剪枝,即当从i开始到9结束的数组长度小于要求的数组长度k时,可以直接跳过循环。
代码:
class Solution {
public:
vector> ans;
vector path;
vector> combinationSum3(int k, int n) {
backtracking(k, n, 1, 0);
return ans;
}
void backtracking(int k, int n, int idx, int sum)
{
if (k < 1)
{
if (sum == n)
ans.push_back(path);
return;
}
for (int i = idx; i <= 9 - (k-1); i++)
{
sum += i;
path.push_back(i);
backtracking(k-1, n, i+1, sum);
sum -= i;
path.pop_back();
}
}
};
链接:17. 电话号码的字母组合
思路:
这道题目本质上还是找字母的组合,只不过这里手动划分了每颗子树的搜索范围。我们可以根据电话号码的按键及对应的字母构建一个哈希表,然后根据输入的数字来获取相对应的字母的集合,该集合即为每颗子树的搜索范围。在for循环里,我们用chars代表了每个数字对应的字母的集合的长度,然后在该数字对应的字母的集合上进行搜索和回溯。
需要注意的是我们使用了numIdx来表示当前所在数字的位数,用来索引digits获取里面的由char表示的2~9之间的数字,然后通过减‘0’的方式把该数字转换成int类型,再用转换好的int类型取hashmap里索引该数字对应的字母表。
在节省空间方面其实可以用更加有效率的数组来做哈希表,因为实际上数字范围一共只有0~9,所以只需要一共大小为10的数组记录每个数字对应的字母即可。
const string letterMap[10] = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz", // 9
};
代码:
class Solution {
public:
unordered_map> hashmap
{
{2, {'a', 'b', 'c'}},
{3, {'d', 'e', 'f'}},
{4, {'g', 'h', 'i'}},
{5, {'j', 'k', 'l'}},
{6, {'m', 'n', 'o'}},
{7, {'p', 'q', 'r', 's'}},
{8, {'t', 'u', 'v'}},
{9, {'w', 'x', 'y', 'z'}}
};
vector ans;
string temp;
vector letterCombinations(string digits) {
backtracking(digits, 0);
return ans;
}
void backtracking(string &digits, int numIdx)
{
if (numIdx > digits.size() - 1)
{
ans.push_back(temp);
return;
}
// 获取当前数字所代表的字母串
vector chars = hashmap[digits[numIdx] - '0'];
// 遍历字母串,把每次遍历的元素放入string
for (int i = 0; i < chars.size(); i++)
{
temp.push_back(chars[i]);
backtracking(digits, numIdx + 1);
// 回溯
temp.pop_back();
}
return;
}
};