题目地址
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = “23”
输出:[“ad”,“ae”,“af”,“bd”,“be”,“bf”,“cd”,“ce”,“cf”]
示例 2:
输入:digits = “”
输出:[]
示例 3:
输入:digits = “2”
输出:[“a”,“b”,“c”]
提示:
0 <= digits.length <= 4
digits[i] 是范围 [‘2’, ‘9’] 的一个数字。
解法一:广度优先搜索的算法
利用队列,首先将第一个数字对应的字母放入到队列中,此时将字符串中的这个数字剔除,以此达到结束循环条件的目的,然后逐个弹出队列中的元素,与新的字母想对应,并压入到队列中,如果此时数字字符串空了,则队列中就是所有的字母组合。
例如:digits = 23
abc def
队列:a-b-c-ad-ae-af-bd-be-bf-cd-ce-cf
代码实现:
# 以下以digits = "23"为例
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits: #首先判断特殊情况,如果数字字符串为空
return [] #返回空即可
dic = {} #定义一个哈希表
dic = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno',
'7': 'pqrs', '8': 'tuv', '9': 'wxyz'} #将相应的数字与字母对应起来
q = collections.deque() #首先初始化一个队列
q.extend(dic[digits[0]]) #首先将数字字符串中的第一个数字对应的字母压入到队列中:print(q)为deque(['a', 'b', 'c'])
digits = digits[1:] #将这个数字从字符串中移除,为了方便构建结束条件,此时赋值后digits[0]是指3
while digits: #当数字字符串不为空时,此时表示还需要有新的字母组合
for i in range(len(q)): #因为每个数字对应的字母均要用来进行字母组合,所以这边需要知道每一层的字母个数
tmp = q.popleft() #首先将第一个元素弹出:tmp依次为a、b、c,首先从队列中弹出a,此时q为deque(['b', 'c'])
print('tmp:',tmp)
for j in range(len(dic[digits[0]])): #将第一个元素弹出,此时需要与第二个数字对应的字母进行组合,每个字母均需要,所以这边要按照长度进行遍历
#此时digits[0]是指3
tmp1 = tmp + dic[digits[0]][j] #将弹出的元素和新的字母进行组合
print('tmp1:',tmp1)
q.append(tmp1) #组合后放入队列中
print('q',q)
digits = digits[1:] #将这个已经组合完成的数字移除
res = [] #因为刚刚元素均存在了队列中,此时需要返回一个数组,所以需要重新初始化一个数组
for p in range(len(q)): #将队列中的每一个元素弹出,并放入到结果数组中
tmp_pop = q.popleft() #将队列中元素弹出
print('tmp_pop',tmp_pop)
res.append(tmp_pop) #放入结果数组中
print('res',res)
return res #返回结果即可
以23为例,print的过程:
tmp: a
tmp1: ad
q deque([‘b’, ‘c’, ‘ad’])
tmp1: ae
q deque([‘b’, ‘c’, ‘ad’, ‘ae’])
tmp1: af
q deque([‘b’, ‘c’, ‘ad’, ‘ae’, ‘af’])
tmp: b
tmp1: bd
q deque([‘c’, ‘ad’, ‘ae’, ‘af’, ‘bd’])
tmp1: be
q deque([‘c’, ‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’])
tmp1: bf
q deque([‘c’, ‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’])
tmp: c
tmp1: cd
q deque([‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’])
tmp1: ce
q deque([‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’])
tmp1: cf
q deque([‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’, ‘cf’])
tmp_pop ad
res [‘ad’]
tmp_pop ae
res [‘ad’, ‘ae’]
tmp_pop af
res [‘ad’, ‘ae’, ‘af’]
tmp_pop bd
res [‘ad’, ‘ae’, ‘af’, ‘bd’]
tmp_pop be
res [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’]
tmp_pop bf
res [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’]
tmp_pop cd
res [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’]
tmp_pop ce
res [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’]
tmp_pop cf
res [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’, ‘cf’]
为了方便看,无注释无print版本:
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
if not digits:
return []
dic = {}
dic = {'2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno',
'7': 'pqrs', '8': 'tuv', '9': 'wxyz'}
q = collections.deque()
q.extend(dic[digits[0]])
digits = digits[1:]
while digits:
for i in range(len(q)):
tmp = q.popleft()
for j in range(len(dic[digits[0]])):
tmp1 = tmp + dic[digits[0]][j]
q.append(tmp1)
digits = digits[1:]
res = []
for p in range(len(q)):
tmp_pop = q.popleft()
res.append(tmp_pop)
return res
解法二:深度优先搜索算法
深度优先搜索算法就是递归回溯了,递归三个需要提前确定的必要条件:输入参数、输出参数以及结束条件,结束条件就是字符串中遍历到最后一个数字对应的字母,也就是深度优先搜索算法,搜索到了最深的位置,所以结束条件就是index == n,输入参数是当前遍历到的数字字符串中的第几个数字index,返回参数就是最后的返回值,参考官方题解,写了下面的递归算法。
例如:digits = 235
abc def jkl
队列:a-ad-adj-ad-adk-ad-adl-ad-a-ae-aej-ae-aek-ae-ael-ae-a-af-afj-af-afk-af-afl-af-a-[]-b-bd-
bdj-bd-…
代码实现:
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
dic = {'2':'abc', '3':'def', '4':'ghi', '5':'jkl', '6':'mno', '7':'pqrs','8':'tuv','9':'wxyz'} #首先定义一个哈希表,把相应的数字和字母对应起来
n = len(digits) #计算给定字符串中数字的长度
if n == 0:
return []
res = [] #初始化返回结果数组
tmp = [] #初始化过渡数组
def dfs(index): #定义递归回溯函数
if index == n: #如果此时递归到了字符串中最后一个数字,则表示第一层深度搜索结束,将结果存储起来
res.append(''.join(tmp)) #注意一下这边存储的时候要把多个字符串组合成一个字符串,利用
#join函数,这边还要注意的是后面会把tmp中的最上面字符弹出,这边利用join函数也同时避免
#了tmp弹出时影响res的目的,不然全部返回空字符串
print('res:',res)
else: #如果这个时候没搜索到最后一层,则
for i in dic[digits[index]]: #逐个遍历当前数字对应的字母
tmp.append(i) #将这个字母加到tmp中
print('tmp1:',tmp)
dfs(index + 1) #因为要把下一个数字对应的字母继续加进去,所以这边index + 1,函数传递下一个位置
tmp.pop() #因为还需要把最后一个数字的字母逐个加进去,所以这边要把最后一个弹出,pop是出栈,后进先出,所以把d弹出去,tmp里值剩下a
#因为上一行的dfs函数遇到结束条件,才回向下执行,所以这边已经完成一次深度的搜索,此时要把最后一个字母弹出,实现下一轮遍历
print('tmp2:',tmp)
dfs(0) #首先执行index = 0,因为都是从第一个字母开始组合
return res #返回结果函数
以23为例,print的过程:
tmp1: [‘a’]
tmp1: [‘a’, ‘d’]
res: [‘ad’]
tmp2: [‘a’]
tmp1: [‘a’, ‘e’]
res: [‘ad’, ‘ae’]
tmp2: [‘a’]
tmp1: [‘a’, ‘f’]
res: [‘ad’, ‘ae’, ‘af’]
tmp2: [‘a’]
tmp2: []
tmp1: [‘b’]
tmp1: [‘b’, ‘d’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’]
tmp2: [‘b’]
tmp1: [‘b’, ‘e’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’]
tmp2: [‘b’]
tmp1: [‘b’, ‘f’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’]
tmp2: [‘b’]
tmp2: []
tmp1: [‘c’]
tmp1: [‘c’, ‘d’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’]
tmp2: [‘c’]
tmp1: [‘c’, ‘e’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’]
tmp2: [‘c’]
tmp1: [‘c’, ‘f’]
res: [‘ad’, ‘ae’, ‘af’, ‘bd’, ‘be’, ‘bf’, ‘cd’, ‘ce’, ‘cf’]
tmp2: [‘c’]
tmp2: []
为了方便看,无注释无print版本:
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
dic = {'2':'abc', '3':'def', '4':'ghi', '5':'jkl', '6':'mno', '7':'pqrs','8':'tuv','9':'wxyz'}
n = len(digits)
if n == 0:
return []
res = []
tmp = []
def dfs(index):
if index == n:
res.append(''.join(tmp))
print('res:',res)
else:
for i in dic[digits[index]]:
tmp.append(i)
dfs(index + 1)
tmp.pop()
dfs(0)
return res