题目描述(中等难度)
给一串数字,每个数可以代表数字键下的几个字母,返回这些数字下的字母的所有组成可能。
解法 回溯法
首先使用哈希表存储每个数字对应的所有可能的字母,然后进行回溯操作。
回溯过程中维护一个字符串,表示已有的字母排列(如果未遍历完电话号码的所有数字,则已有的字母排列是不完整的)。该字符串初始为空。每次取电话号码的一位数字,从哈希表中获得该数字对应的所有可能的字母,并将其中的一个字母插入到已有的字母排列后面,然后继续处理电话号码的后一位数字,直到处理完电话号码中的所有数字,即得到一个完整的字母排列。然后进行回退操作,遍历其余的字母排列。
回溯算法用于寻找所有的可行解,如果发现一个解不可行,则会舍弃不可行的解。在这道题中,由于每个数字对应的每个字母都可能进入字母组合,因此不存在不可行的解,直接穷举所有的解即可。
Java
public class Letter_Combinations_of_a_Phone_Number {
public static 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 static 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[]) {
String digits= "23";
List<String> ans=letterCombinations(digits);
System.out.println(ans);
}
}
有几点需要注意下:
为什么使用StringBuffer而不使用String?
简要的说, String
类型和 StringBuffer
类型的主要性能区别其实在于 String
是不可变的对象, 因此在每次对 String
类型进行改变的时候其实都等同于生成了一个新的 String
对象,然后将指针指向新的 String
对象,所以经常改变内容的字符串最好不要用 String
,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后.
而如果是使用 StringBuffer
类则结果就不一样了,每次结果都会对 StringBuffer
对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer
,特别是字符串对象经常改变的情况下。而在某些特别情况下, String
对象的字符串拼接其实是被 JVM 解释成了 StringBuffer
对象的拼接,所以这些时候 String
对象的速度并不会比 StringBuffer
对象慢, String
效率是远要比 StringBuffer
快的.
Python
class Solution(object):
def letterCombinations(self, digits):
combinations = []
if len(digits)==0:
return combinations
combination=''
phoneMap = {"2": "abc","3": "def","4": "ghi" ,"5": "jkl","6": "mno","7": "pqrs","8": "tuv","9": "wxyz"}
self.backtrace(combinations,phoneMap,digits,0,combination)
return combinations
def backtrace(self,combinations,phoneMap,digits,index, combination):
if(index==len(digits)):
combinations.append(combination)
else:
digit = digits[index]
letters = phoneMap.get(digit)
lettercount = len(letters)
for i in range(lettercount):
combination=''.join([combination,letters[i]])
self.backtrace(combinations,phoneMap,digits,index+1,combination)
combination=combination[:index]
有几点需要注意下
- java的
HashMap
对应的就是python中的dict
- java中的
String
和StringBuilder
类型对应python中的字符串类型 - python中的字符串添加元素使用的是
join
方法,java中用的是append
- java中删除
StringBuilder
类型的元素,是先找到其索引,采用deleteCharAt
删除,而python这里我们直接将指定元素排除在外即可 - python中更新字典元素采用
update
,java采用put
参考文献
- https://blog.csdn.net/rmn190/article/details/1492013