题目:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = ""
输出:[]
示例 3:
输入:digits = "2"
输出:["a","b","c"]
解题过程:
关键字:“所有符合”
凡是出现“找到符合条件所有组合的解”的时候,都要使用搜索算法,从所有空间解里,找到符合要求的答案,常见的搜索算法无外乎深度和广度优先搜索两种
一般而言, 利用自顶向下的递归实现深度搜索,是最自然的想法,在这个过程中需要找到子问题,在当前递归层结合子问题的结果来解决原问题。
所谓的子问题可以看做是输入简化后的情况,比如对于树问题,子问题就是当前节点的子树问题,对于字符串而言,子去除了当前字符,剩余字符串的问题。我们可以通过递归调用函数来获得子问题的解。
比如说
2:abc
3:def
原问题是23的字符串组合,子问题就是3的字符串组合,子问题的解为“def”
则原问题的解是2的字符串当做前缀,添加到到子问题的解之前。
ad,ae,af,bd,be,bf,cd,ce,cf
在代码中,对于所有递归,第一步都是先定义递归的出口。
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");
}};
backtrack(combinations, phoneMap, digits, 0, new StringBuffer());
return combinations;
}
public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {
if (index == digits.length()) {
combinations.add(combination.toString());
} else {
char digit = digits.charAt(index);
String letters = phoneMap.get(digit);
int lettersCount = letters.length();
for (int i = 0; i < lettersCount; i++) {
combination.append(letters.charAt(i));
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.deleteCharAt(index);
}
}
}
}
(2)广度优先搜索
基本上都要使用队列来做辅助结构,其核心是从当前节点出发,得到的解逐步加入队列,然后再向临近节点扩散,从而得到结果。
上面的例子,2的结果abc先出来,然后挨个对应3的字符串