提问人:trying2learn 提问时间:11/2/2022 最后编辑:trying2learn 更新时间:11/5/2022 访问量:108
尝试使用递归解决数字到助记符问题
Trying to solve a number to mnemonics problem using recursion
问:
给定一个长度为非零的字符串化电话号码,编写一个函数,以任何顺序返回此电话号码的所有助记符。
`
def phoneNumberMnemonics(phoneNumber, Mnemonics=[''], idx=0):
number_lookup={'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']}
if idx==len(phoneNumber):
return Mnemonics
else:
new_Mnemonics=[]
for letter in number_lookup[phoneNumber[idx]]:
for mnemonic in Mnemonics:
new_Mnemonics.append(mnemonic+letter)
phoneNumberMnemonics(phoneNumber, new_Mnemonics, idx+1)
`
如果我使用输入“1905”,我的函数将输出 null。在 return 语句之前使用 print 语句,我可以看到列表助记符是
['1w0j', '1x0j', '1y0j', '1z0j', '1w0k', '1x0k', '1y0k', '1z0k', '1w0l', '1x0l', '1y0l', '1z0l']
这是正确答案。为什么返回 null?
我还不是很擅长实现递归(还?),感谢您的帮助。
答:
为递归的最深调用生成了正确的列表(助记符)。但是,它没有传递回以前的调用。
要解决此问题,不仅需要在“else”块中返回助记符,还需要将其设置为等于递归函数 phone Number Mnemonics 的输出。
def phoneNumberMnemonics(phoneNumber, Mnemonics=[''], idx=0):
number_lookup={'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']}
print(idx, len(phoneNumber))
if idx==len(phoneNumber):
pass
else:
new_Mnemonics=[]
for letter in number_lookup[phoneNumber[idx]]:
for mnemonic in Mnemonics:
new_Mnemonics.append(mnemonic+letter)
Mnemonics=phoneNumberMnemonics(phoneNumber, new_Mnemonics, idx+1)
return Mnemonics
我仍然觉得我对递归的理解缺乏复杂性。欢迎提供建议、反馈和澄清。
这个问题有不同的递归表达式,但当你开始时,最简单的思考是“纯函数”表达式。这意味着您永远不会改变递归确定的值。相反,计算新的字符串:列表等(Python不会给你关于字符串的选择;它们总是不可变的。通过这种方式,您可以只考虑值,而不是它们如何存储以及更改它们的原因,这非常容易出错。
思考这个问题的一个纯功能方式是这样的:
如果电话号码为空字符串,则返回值只是一个包含空字符串的列表。
否则,将数字分解为其第一个字符和其余字符。递归获取其余部分的所有助记符 R。然后找到与第一个字母对应的所有字母,并将每个字母都预置到 R 的每个成员之前,以创建一个新字符串(这称为笛卡尔叉积,它经常在递归中出现。返回所有这些字符串。
在此表达式中,纯函数的形式为
M(n: str) -> list[str]:
它接受一串数字并返回助记符列表。
把这个想法放到python中相当简单:
LETTERS_BY_DIGIT = {
'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'],
}
def mneumonics(n: str):
if len(n) == 0:
return ['']
rest = mneumonics(n[1:])
first = LETTERS_BY_DIGIT[n[0]]
rtn = [] # A fresh list to return.
for f in first: # Cartesian cross:
for r in rest: # first X rest
rtn.append(f + r); # Fresh string
return rtn
print(mneumonics('1905'))
请注意,此代码根本不会改变递归返回值。它创建一个新字符串的新列表。rest
当你掌握了所有的 Python 习语后,你会看到一种更流畅的方法来编写同样的东西:
def mneumonics(n: str):
return [''] if len(n) == 0 else [
c + r for c in LETTERS_BY_DIGIT[n[0]] for r in mneumonics(n[1:])]
这是解决此问题的最有效代码吗?绝对不行。但无论如何,这不是一件非常实际的事情。在你牢牢掌握这种思维方式之前,最好选择一个简单、正确的、易于理解的解决方案,而不是担心效率。
正如其他人所说,如果这是一个生产需求,那么在这个问题上使用递归并不是一个好的选择。
评论
return