今天想和大家分享一道经典的LeetCode回溯算法题目——电话号码的字母组合(第17题)。这道题看似简单,但蕴含着回溯算法的核心思想,是理解递归和深度优先搜索(DFS)的绝佳案例。
问题的实际场景很常见:当我们用老式手机键盘输入数字时,每个数字键对应多个字母(比如2对应abc,3对应def等)。现在给定一串数字,要求返回所有可能的字母组合。例如输入"23",输出应该是["ad","ae","af","bd","be","bf","cd","ce","cf"]。
首先我们需要明确几个关键点:
回溯算法特别适合解决这类"组合"问题,因为它能系统地枚举所有可能性。其核心思想是:
对于这道题,我们可以把每个数字看作一层,每层的选择是该数字对应的所有字母。
python复制def letterCombinations(digits):
if not digits:
return []
digit_map = {
'2': 'abc',
'3': 'def',
'4': 'ghi',
'5': 'jkl',
'6': 'mno',
'7': 'pqrs',
'8': 'tuv',
'9': 'wxyz'
}
result = []
def backtrack(index, current):
if index == len(digits):
result.append(''.join(current))
return
for letter in digit_map[digits[index]]:
current.append(letter)
backtrack(index + 1, current)
current.pop()
backtrack(0, [])
return result
最坏情况下,每个数字对应4个字母(7和9),所以时间复杂度是O(4^n),其中n是输入数字的长度。
主要消耗在递归调用栈和结果存储上:
可以优化current参数为字符串,避免频繁的append/pop操作:
python复制def backtrack(index, current_str):
if index == len(digits):
result.append(current_str)
return
for letter in digit_map[digits[index]]:
backtrack(index + 1, current_str + letter)
虽然回溯更直观,但也可以用BFS迭代实现:
python复制from collections import deque
def letterCombinations(digits):
if not digits:
return []
digit_map = {...} # 同上
queue = deque([''])
for digit in digits:
level_size = len(queue)
for _ in range(level_size):
current = queue.popleft()
for letter in digit_map[digit]:
queue.append(current + letter)
return list(queue)
特别注意输入为空字符串的情况,应该返回空列表而非包含空字符串的列表。
虽然电话号码长度通常不会太长,但如果输入很长,Python可能有递归深度限制。这时迭代解法更安全。
题目通常不要求特定顺序,但测试用例可能检查顺序。标准回溯实现会自然按数字和字母顺序生成组合。
这类组合问题在实际中有很多应用场景:
理解回溯算法后,可以轻松解决许多类似问题,如:
在实际编码时,有几点特别值得注意:
这道题看似简单,但完整实现并理解其背后的思想,对掌握回溯算法非常有帮助。建议初学者可以手动模拟小例子(如"23")的执行过程,加深对递归调用的理解。