题目
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
思路
没什么好说的,直接dfs即可,需要注意的是,这里对数字的顺序不做要求,即:“ab” 和 “ba” 是同一个答案,因此我们不需要使用 hasUsed 标识路径,直接使用 index 索引完成顺序遍历数字字符串即可,那么提供原版代码和改进时间性能的代码。
代码
原版代码:使用Map存储对应关系,用 StringBuffer 存储组装结果,在dfs过程中在每个对应的 index 索引位置上取出其中一个字符组装结果并进入递归,在递归结束后再删除这个字符,接着取出下一个字符组装结果,直到该数字对应的字符都被遍历完。
public class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<>();
if(digits.length()==0)
return combinations;
Map<Character,String> phoneMap = new HashMap<>();
//
phoneMap.put('2',"abc");
phoneMap.put('3',"def");
phoneMap.put('4',"ghi");
phoneMap.put('5',"jkl");
phoneMap.put('6',"mno");
phoneMap.put('7',"pqrs");
phoneMap.put('8',"tuv");
phoneMap.put('9',"wxyz");
//不同顺序相同字符集合也是同一个答案,因此从索引为0开始递归调用,
//因为不要求字典序,所以从index=0开始,一定可以遍历到index=n-1
bactrack(combinations,phoneMap,digits,0,new StringBuffer());
return combinations;
}
//递归函数,控制参数其实也就只有 int index 和 StringBuffer combination
private void bactrack(List<String> combinations,Map<Character,String> phoneMap,
String digits,int index,StringBuffer combination){
//递归终止条件
if(index==digits.length())
combinations.add(combination.toString());
else{
//取出index所在的数字
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));
//递归,index+1,找到下一个数字对应的字符
bactrack(combinations,phoneMap,digits,index+1,combination);
//回退,删除该字符,等待另外的循环里将其他字符放在此处
combination.deleteCharAt(index);
}
}
}
性能提升:用数组替换HashMap,使用char[] 存储组装结果,比起 StringBuffer ,字符数组不需要回退,因为索引相同的字符最终都会覆盖旧值。
public class Solution {
private char[][] lettersArray = {
{'a','b','c'},{'d','e','f'},{'g','h','i'},
{'j','k','l'},{'m','n','o'},{'p','q','r','s'},
{'t','u','v'},{'w','x','y','z'}
};
// 方法2:运行速度快:dfs的每次循环中由于不需要进行回退操作,因此提升了速度
// 巧妙地使用了char[]来进行处理,不需要考虑回退的问题,因为每次写入新值都会覆盖掉旧值
public List<String> letterCombinations2(String digits) {
List<String> ret = new ArrayList<>();
if(digits==null||digits.length()==0)
return ret;
char[] chars = digits.toCharArray();
dfs(chars,new char[chars.length],0,ret);
return ret;
}
private void dfs(char[] chars,char[] result,int index,List<String> ret){
if(index==chars.length){
ret.add(new String(result));
return;
}
// 因为这里使用的是char[]数组的形式组成答案,因此不需要回退,每次for循环会自动覆盖该位置对应的值
char[] letters = lettersArray[chars[index] -'2'];
for (int i = 0; i < letters.length; i++) {
result[index] = letters[i];
dfs(chars,result,index+1,ret);
}
}
}