问题:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同 拼音九键)。注意 1 不对应任何字母。
思路:
for
循环嵌套来解决,但是发现输入数组不固定(这种情况下应该使用回溯算法–也就是递归)。但是可以发现for
循环嵌套的层数取决于输入字符串digits
的个数。对于输入字符串23
,本质就是求2和3对应字符的排列组合,可以将问题抽象为遍历下面这颗决策树,记录到每个叶子节点的路径。此时需要考虑三个问题:
class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<String>();
if (digits.length() == 0) {
return combinations;
}
Map<Character, String> phoneMap = new HashMap<Character, String>() {{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
StringBuffer sb = new StringBuffer();
dfs(phoneMap, combinations, digits, 0, sb);
return combinations;
}
public void dfs(Map<Character, String> phoneMap, List<String> combinations, String digits, int index, StringBuffer res){
//回溯结束条件
if(index == digits.length()){
//加入路径
combinations.add(res.toString());
} else {
char number = digits.charAt(index);
String dict = phoneMap.get(number);
//选择列表
for(int i = 0; i < dict.length(); i++){
char ch = dict.charAt(i);
//做选择
res.append(ch);
//
dfs(phoneMap, combinations, digits, index + 1, res);
//撤销选择
res.deleteCharAt(index);
}
}
}
}
以输入字符串"23"为例,首先需要在队列中添加一个元素 相当于这棵树的根节点,到根节点的路径为空。然后将到根节点路径出队(即最先入队的空字符串,注意队列中只存放到这层节点的路径),"2"对应的字符(对应决策树第二层节点)直接放入队列,因为从根节点到第二层节点的路径就是节点本身,比如:"" + 'a' = "a"
。接下来是第三层,参考上面的决策树,我们知道第二层的每个节点的所有孩子对应”3“表示的所有字符,所以到第三层节点的路径就是"2"和”3“对应字符的组合,即出队"a"分别与{“d”, “e”, “f”}(3对应的字符)组成{“ad”, “ae”, “af”}并依次入队作为从节点"a"到其孩子节点的路径,“b”,"c"节点同理。其他情况类似。
class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<String>();
if (digits.length() == 0) {
return combinations;
}
Map<Character, String> phoneMap = new HashMap<Character, String>() {{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
Queue<String> queue = new LinkedList<>();
//首先需要在队列中添加一个元素 相当于这棵树的根节点,到根节点的路径为空。
queue.offer("");
StringBuffer sb = new StringBuffer();
for(int i = 0; i < digits.length(); i++){
String dict = phoneMap.get(digits.charAt(i));
int size = queue.size();
while(size > 0) {
sb.append(queue.poll());
for(int j = 0; j < dict.length(); j++){
sb.append(dict.charAt(j));
queue.offer(sb.toString());
sb.deleteCharAt(i);
}
//清空StringBuffer
sb.delete(0, sb.length());
size--;
}
}
//将队列中的组合存入list中并返回
while(!queue.isEmpty()) {
combinations.add(queue.poll());
}
return combinations;
}
}