17. Lexicographical Letter Combinations of Phone Digits
Origin: Lexicographical Letter Combinations of Phone Digits
Given a string of digits where ‘2’-‘9’ map to letters (like on a phone keypad) and ‘0’,‘1’ map to themselves, return all possible letter combinations in lexicographical order.
Mapping:
- ‘2’ → [a, b, c]
- ‘3’ → [d, e, f]
- ‘4’ → [g, h, i]
- ‘5’ → [j, k, l]
- ‘6’ → [m, n, o]
- ‘7’ → [p, q, r, s]
- ‘8’ → [t, u, v]
- ‘9’ → [w, x, y, z]
- ‘0’ → [‘0’]
- ‘1’ → [‘1’]
Example 1
Input: digits = “23”
Output: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’, ‘cf’]
Explanation: ‘2’ → [a, b, c], ‘3’ → [d, e, f]. For each letter of ‘2’, combine with each letter of ‘3’.
Example 2
Input: digits = “203”
Output: [‘a0d’, ‘a0e’, ‘a0f’, ‘b0d’, ‘b0e’, ‘b0f’, ‘c0d’, ‘c0e’, ‘c0f’]
Explanation: ‘2’ → [a, b, c], ‘0’ → [‘0’], ‘3’ → [d, e, f]. For each letter of ‘2’, insert ‘0’, then combine with each letter of ‘3’.
Input Format
A string digits containing only characters ‘0’-‘9’.
Constraints
- 0 <= digits.length <= 10
- digits[i] is one of ‘0’-‘9’
Output Format
Return a STRING_ARRAY of all combinations, separated by spaces, in lexicographical order.
Sample Input 0
23
Sample Output 0
ad ae af bd be bf cd ce cf
Sample Input 1
203
Sample Output 1
a0d a0e a0f b0d b0e b0f c0d c0e c0f
函数契约
// 输入:digits(字符串,只含 '0'-'9')
// 输出:所有可能的字母组合列表,字典序
// 边界:空字符串 → [] 或 [""];单个数字 → 对应字母列表
边界表
| 场景 | 返回什么 |
|---|---|
| 空字符串 | [] 或 [""] |
| 单个数字 “2” | [a, b, c] |
| “0” 或 “1” | [“0”] 或 [“1”] |
| “23” | 9 个组合 |
| 正常场景 | 所有组合的笛卡尔积 |
Resolution
我的解法
function letterCombinations(digits: string): string[] {
if (!digits || digits.length === 0) {
return []
}
const result: string[] = []
const letterMap: { [key: string]: string[] } = {
"0": ["0"],
"1": ["1"],
"2": ["a", "b", "c"],
"3": ["d", "e", "f"],
"4": ["g", "h", "i"],
"5": ["j", "k", "l"],
"6": ["m", "n", "o"],
"7": ["p", "q", "r", "s"],
"8": ["t", "u", "v"],
"9": ["w", "x", "y", "z"]
}
const backtrack = (index: number, path: string) => {
if (index === digits.length) {
result.push(path)
return
}
const letters = letterMap[digits[index]]
for (const letter of letters) {
backtrack(index + 1, path + letter)
}
}
backtrack(0, "")
return result
}解题思路
经典回溯。对每个数字,从它对应的字母列表里选一个,拼接到 path,递归下一个数字。
- 建数字到字母的映射表(注意 7 和 9 是四个字母,0 和 1 映射到自身)
backtrack(index, path):index 是当前处理到第几个数字,path 是当前拼接的字符串- index 等于 digits.length 时,path 就是一个完整组合,存入结果
- 否则遍历当前数字对应的字母,逐个递归
对比标准解法
标准解法有两种写法:
回溯(和你的解法一致):
def letterCombinations(digits):
if not digits: return []
d = ["abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
result = []
def backtrack(index, path):
if index == len(digits):
result.append(path)
return
for letter in d[int(digits[index])-2]:
backtrack(index + 1, path + letter)
backtrack(0, "")
return result区别:标准解法用索引偏移(int(digits[index])-2)访问数组,省了建 Map 的步骤。你的用 Map 更直观,可读性更好,两者性能一样。
迭代法(非递归):
def letterCombinations(digits):
if not digits: return []
d = ["abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"]
result = [""]
for digit in digits:
letters = d[int(digit)-2]
result = [a + b for a in result for b in letters]
return result迭代法不需要递归栈,思路是:每处理一个数字,把已有结果和当前字母列表做笛卡尔积。比如 result = [“a”,“b”,“c”],处理 ‘3’,变成 [“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]。
你的回溯解法和标准解法完全一致,面试够用。迭代法作为了解,面试时如果面试官追问”能不能不用递归”,你可以写出迭代版。
复杂度
- 时间:O(4^n),每个数字最多 4 个字母,n 个数字
- 空间:O(n),递归栈深度
测试用例
| 输入 | 输出 | 场景 |
|---|---|---|
| ”23” | 9 个组合 | 基本用例 |
| "" | [] | 空字符串 |
| ”2” | [a,b,c] | 单数字 |
| ”0” | [“0”] | 数字 0 |
| ”1” | [“1”] | 数字 1 |
| ”7” | [p,q,r,s] | 四字母数字 |
全部通过。
参考来源
- 相关题型:回溯算法
- 相关文章:算法解题流程:从读题到提交的七步
- 相关题目:13. Generate Valid Angle Bracket Sequences — 同样是回溯,一个是括号配对,一个是字母组合