📝个人主页:五敷有你
🔥系列专栏:算法分析与设计
⛺️稳中求进,晒太阳
题目
给定一个仅包含数字
2-9
的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例
示例 1:
输入:digits = "23" 输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = "" 输出:[]
示例 3:
输入:digits = "2" 输出:["a","b","c"]
思路(回溯)
回溯是一种通过不断尝试所有可能的解决方案来解决问题的算法。它的基本思路是逐步构建解决方案,当发现当前方案不可行时,进行回溯(撤销上一步的选择),并尝试其他的选择,直到找到问题的解决方案或者确定不存在解决方案为止。以下是回溯算法的一般套路:
明确问题的决策树结构: 将问题转化为一个决策树,每个节点代表一个决策点,通过递归的方式遍历这棵决策树,尝试所有可能的选择。
编写递归函数: 设计一个递归函数来遍历决策树。函数的参数通常包括当前状态、已经做出的选择等。
确定终止条件: 在递归函数中,明确何时可以终止递归,一般是当达到问题的边界条件时,如处理到最后一个数字时。
对每个决策点进行选择与撤销选择: 在递归函数中,对当前决策点做出一个选择,并根据这个选择递归地处理下一个决策点;在处理完当前决策点后,需要撤销这个选择,以便尝试其他选择。
处理剪枝: 如果问题中存在一些无效的分支,可以通过剪枝来减少搜索空间,提高效率。剪枝的条件可以根据具体问题而定。
处理解的存储与处理: 在找到一个解时,根据具体需求进行解的存储或处理。可能需要将解存储起来,或者直接在递归函数中进行处理。
清理状态: 在回溯的过程中,需要及时清理状态,以便下一次搜索。这包括清理选择,恢复状态等。
回溯算法的实现通常比较灵活,因为它适用于各种问题,包括组合问题、排列问题、子集问题等。在具体解决问题时,需要根据问题的特点来设计具体的回溯算法。
算法设计与分析
-
首先,创建一个映射表,将数字与字母的对应关系存储起来。可以使用HashMap来实现这个映射。
-
然后,使用回溯算法进行递归。递归函数应该接受三个参数:当前正在处理的数字字符串、当前索引、当前正在生成的组合字符串。
-
在递归函数中,首先检查当前索引是否越界,如果越界,则将当前生成的组合字符串加入结果列表中,并返回。
-
如果当前索引没有越界,取出当前索引对应的数字,并获取其对应的字母列表。
-
遍历这个字母列表,每次取出一个字母,将其加入当前生成的组合字符串中,并调用递归函数处理下一个数字。
-
处理完当前数字后,需要回溯到上一状态,将刚才加入的字母从组合字符串中移除,继续遍历其他字母。
-
当所有数字处理完毕后,递归函数结束。
-
最后,返回结果列表即可
代码实现
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);
}
}
}
}