给定一个仅包含数字2-9的字符串,返回所有它能够表示的字母组合。答案可以按任意顺序返回
给出数字到字母的映射如电话按键一样。注意1不对应任何字母。
示例:
输入:"23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"] 输入:"" 输出:[] 输入:"2" 输出:["a","b","c"]
这个题目就是类似于给出所有的排列组合,而且是有顺序的排列组合,这就比如走路线问题。假如你回家坐公交一样,在开始可以做101,102,103路公交,然后到成才路要倒车,可以做201,202,203公交到家,问你到家可以选择的回家路线。
这是不是一个很简单的问题。可以选择做101-201回家,也可以选择做101-202回家,总过的可能路线是101-201,101-202,101-203,102-201,102-202,102-203,103-201,103-202,103,-203。这个如果用图表示的话,是不是可以如下所示
看到了这张图是很正常就能得出来的想法,但是你觉得这个图画的不够高级,刚好今天上午你在学校刚好上课学到了n叉树,你就很高级的画出来了这种图
这个时候你只需要遍历所有的路径就可以得到所有能够回到家的可能
在这道题中,就是类似于这种问题,相应的数字对应着相应的字母,给出多少数字就相当于你回家需要倒几次车,每个数字对应多少字母就是你回家有多少中选择的公交,终止条件从家变成空就行最后遍历整个数的路径就可以。
所有节点要执行的操作都是一样的,就是逐个的遍历求解,不管在哪个位置的节点,其要执行的就是一步步往下走。
这就转换为了树形结果的遍历,只需要一点点的遍历所有的路径,就可以得出最终的解
可以选择回溯算法求解,就从第一个开始,一直往下走,直到走到尾,然后把所有的路线走完为止。
首先需要用哈希表存储数字和字母的对应关系,然后才可以进行回溯
private 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"); }};
然后就需要两个变量,一个用来保存每次的一个结果,另一个是列表用来保存每次的结果。
用StingBuffer来记录每次的结果,每到一个节点,就记录该节点加入到StringBuffer,
直到最后一个节点,将该StringBuffer记录到总结果列表中
然后移除这个点,接着往下遍历
直到所有的节点遍历结束
每个路径的中止条件就是路径的长度为digits.length
每个节点的中止条件就是循环次数和对应的字母个数一样
// 数字和字母的对应关系 private 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"); }}; public List<String> letterCombinations(String digits){ // 放置最终结果 List<String> combinations = new ArrayList<>(); // 如果输入为空,返回空列表 if (digits.length() == 0){ return combinations; } // 获得digits的长度 int len = digits.length(); // 0为最开始的索引,从第一个节点开始遍历 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); } } }
测试
public static void main(String[] args) { LC17 lc = new LC17(); System.out.println(lc.letterCombinations("23")); }
结果
["ad","ae","af","bd","be","bf","cd","ce","cf"]