题目:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
输入:digits = ""
输出:[]
输入:digits = "2"
输出:["a","b","c"]
------------------------------
思考:
从示例上来说,输入"23",最直接的想法就是两层for循环遍历了吧,正好把组合的情况都输出了。
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
大家应该感觉出和77.组合 (opens new window)遇到的一样的问题
,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
理解本题后,要解决如下三个问题:
数字和字母如何映射
两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
输入1 * #按键等等异常情况
数字和字母如何映射
可以使用map或者定义一个二维数组,例如:string letterMap[10],来做映射,
我这里定义一个二维数组,代码如下:
const string letterMap[10] = {
"",
"",
"abc",
"def",
"ghi",
"jkl",
"mno",
"pqrs",
"tuv",
"wxyz",
};
回溯法来解决n个for循环的问题
例如:输入:"23",抽象为树形结构,如图所示:
图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,
输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。
回溯三部曲:
确定回溯函数参数
首先需要一个字符串s来收集叶子节点的结果,然后用一个字符串数组result保存起来,
这两个变量我依然定义为全局。
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
注意这个index可不是 77.组合 和216.组合总和III 中的startIndex了。
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串)
同时index也表示树的深度。
代码如下:
vector<string> result;
string s;
void backtracking(const string& digits, int index)
确定终止条件
例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。
那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)
然后收集结果,结束本层递归。
代码如下:
if (index == digits.size()) {
result.push_back(s);
return;
}
确定单层遍历逻辑
首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。
然后for循环来处理这个字符集,代码如下:
int digit = digits[index] - '0';
string letters = letterMap[digit];
for (int i = 0; i < letters.size(); i++) {
s.push_back(letters[i]);
backtracking(digits, index + 1);
s.pop_back();
}
注意这里for循环,可不像是在回溯算法:求组合问题! (opens new window)和回溯算法:求组合总和!
中从startIndex开始遍历的。
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合和
216.组合总和III 都是是求同一个集合中的组合!
注意:输入1 * #按键等等异常情况
代码中最好考虑这些异常情况,但题目的测试数据中应该没有异常情况的数据,所以我就没有加了。
但是要知道会有这些异常,如果是现场面试中,一定要考虑到!
-------------------------
代码:
class Solution{
List<String> res = new ArrayList<>();
StringBuilder temp = new StringBuilder();
public List<String> letterCombinations(String digits){
if(digits==null || digits.length()==0) return new ArrayList<>();
String[] numString={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
backTracking(digits,numString,0);
return res;
}
public void backTracking(String digits,String[] numString,int num){
if(num==digits.length()){
res.add(temp.toString());
return;
}
String str = numString[digits.charAt(num)-'0'];
for(int i = 0;i < str.length();i++){
temp.append(str.charAt(i));
backTracking(digits,numString,num+1);
temp.deleteCharAt(temp.length()-1);
}
}
}
力扣链接