字母组合"杀手锏":5分钟攻克电话号码的排列组合
👉 今天带你轻松掌握 LeetCode 17 题「电话号码的字母组合」
大家好,我是忍者算法。今天要聊的这道题,是面试中的经典题目,它不仅考察了递归回溯的思维,更是字符串处理的典型案例。来看看如何优雅地解决它!
🤔 从生活场景说起
还记得诺基亚手机的九宫格键盘吗?
- 按键2对应"abc"
- 按键3对应"def"
- 按键4对应"ghi"
…
当我们要输入"hello"时,需要按:44-33-555-555-666
这个场景,其实就是今天算法题的反向操作!
💡 题目剖析
LeetCode 17 要求我们:
给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。
输入:"23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
关键点在于:
- 每个数字对应多个字母
- 需要找出所有可能的组合
就像在九宫格键盘上:
- 按下"2",可能是"a"、“b"或"c”
- 按下"3",可能是"d"、“e"或"f”
😅 新手常见误区
很多人一开始会想:用多层循环搞定!
// ❌ 错误示范
for(char c1 : getChars(digits.charAt(0))) {
for(char c2 : getChars(digits.charAt(1))) {
result.add("" + c1 + c2);
}
}
这样做的问题:
- 代码死板:输入长度不固定怎么办?
- 扩展性差:如果需求变化就要改很多代码
🚀 递归回溯:优雅的解法
来看看高手是怎么做的:
class Solution {
// 建立数字到字母的映射
private String[] letterMap = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz" // 9
};
public List<String> letterCombinations(String digits) {
List<String> res = new ArrayList<>();
if(digits == null || digits.length() == 0)
return res;
backtrack(res, digits, 0, new StringBuilder());
return res;
}
private void backtrack(List<String> res, String digits, int index, StringBuilder path) {
// 到达叶子节点,收集结果
if(index == digits.length()) {
res.add(path.toString());
return;
}
// 当前数字对应的所有可能字母
String letters = letterMap[digits.charAt(index) - '0'];
for(char letter : letters.toCharArray()) {
path.append(letter);
backtrack(res, digits, index + 1, path);
path.deleteCharAt(path.length() - 1);
}
}
}
这就像:
- 拿起手机,准备输入
- 每按一个数字,就有多个字母可选
- 选择一个字母,继续下一个数字
- 直到输入完所有数字,就得到一种组合
🎯 面试常见追问
-
为什么用递归回溯?
- 问题具有"选择"的特征
- 需要尝试所有可能性
- 符合"树形结构"的思维模型
-
时间复杂度是多少?
- O(3^N × 4^M)
- N是对应三个字母的数字个数
- M是对应四个字母的数字个数(比如7和9)
-
如何优化内存使用?
- 使用StringBuilder代替String
- 复用路径变量而不是创建新的
📚 解题技巧总结
记住这个"回溯三部曲":
- 选择:append当前字母
- 探索:递归处理下一个数字
- 撤销:删除当前字母
作者:忍者算法
公众号:忍者算法
🎁 回复【刷题清单】获取LeetCode高频面试题合集
🧑💻 回复【代码】获取多语言完整题解
💡 回复【加群】加入算法交流群,一起进步
#算法面试 #LeetCode #回溯算法 #编程进阶