今日主要总结一下,17. 电话号码的字母组合
题目:17. 电话号码的字母组合
题目描述:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
示例 2:
输入:digits = “”
输出:[]
示例 3:
输入:digits = “2”
输出:[“a”,“b”,“c”]
提示:
0 <= digits.length <= 4
digits[i] 是范围 [‘2’, ‘9’] 的一个数字。
本题重难点
从示例上来说,输入"23",最直接的想法就是两层for循环遍历了,正好把组合的情况都输出了。
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环…,如果是输入n个数字,就对应n层for循环,根本写不出来代码!
大家应该感觉出和77.组合 遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
理解本题后,要解决如下两个问题:
- 数字和字母如何映射
- 两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
一、正确解法
C++代码
class Solution {
public:
vector<string> letterMap = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
vector<string> res;
string s;
void backtracing(string digits, int index){
if(index == digits.size()){// if(s.size() == digits.size())也没问题
res.push_back(s);
return;
}
int digit = digits[index] - '0';
//把输入的数字字符串对应一位转成int 比如把"23"的"2"转成2
string letters = letterMap[digit];
for(int i = 0; i < letters.size(); i++){
s.push_back(letters[i]);
backtracing(digits, index + 1);
s.pop_back();
}
return;
}
vector<string> letterCombinations(string digits) {
s.clear();
res.clear();
if (digits.size() == 0) {
return res;
}
backtracing(digits, 0);
return res;
}
};
注意:
-
这里值得讲解是递归函数backtracing()参数列表有一个参数就是int型的index。
注意这个index可不是 77.组合和216.组合总和III 中的startIndex了。
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
-
注意这里for循环,可不像是在回溯算法求77. 组合和216.组合总和III中从startIndex开始遍历的。
startIndex的核心作用是用于去重
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合和216.组合总和III都是是求同一个集合中的组合。所以当从一个集合中取元素的时候就需要startIndex ,而从两个及以上元素中去元素就不需要startIndex了
总结
1. 算法思想总结:当解决问题需要使用n层for循环,根本写不出来代码这个时候就要想起来使用递归了!!!
2. 关于使不使用startIndex的问题:
startIndex的核心作用是用于去重
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合和216.组合总和III都是是求同一个集合中的组合。