Для заданного строкового номера телефона ненулевой длины напишите функцию, которая возвращает все мнемоники для этого номера телефона в любом порядке.
`
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», моя функция выводит ноль. Используя оператор печати прямо перед оператором возврата, я вижу, что мнемоника списка
['1w0j', '1x0j', '1y0j', '1z0j', '1w0k', '1x0k', '1y0k', '1z0k', '1w0l', '1x0l', '1y0l', '1z0l']
Какой правильный ответ. Почему возвращается ноль?
Я не очень хорошо разбираюсь в рекурсии (пока?), ваша помощь приветствуется.
Спасибо @Gene за ваш ответ. У меня есть оператор return в пятой строке. Не уверен, что понимаю, что не так.
этот вопрос лучше решить без рекурсии.
@D.L, не могли бы вы объяснить, почему? Вы имеете в виду, потому что он добавляет O (n) памяти из-за стека вызовов, или есть другая причина?
@ trying2learn, да, это в значительной степени так, плюс, как правило, он медленнее, чем голый цикл for или while. Одна глава этой книги конкретно посвящена рекурсии и рекурсивным процессам: amazon.co.uk/dp/B0BHL2XKCR, которая может быть вам полезна.






Правильный список (мнемоника) был сгенерирован для самого глубокого вызова рекурсии. Однако он не был передан обратно на предыдущие вызовы.
Чтобы исправить это, мнемоника не только должна быть возвращена в блоке «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:])]
Является ли это наиболее эффективным кодом для решения этой проблемы? Точно нет. Но в любом случае это не очень практично. Лучше найти простое, правильное решение, которое легко понять, чем беспокоиться об эффективности, пока вы не освоите этот способ мышления.
Как уже говорили другие, использование рекурсии вообще для этой проблемы - не лучший выбор, если бы это было производственным требованием.
Большое спасибо за ваше руководство. Существуют ли общие рекомендации, когда рекурсия является хорошим выбором?
Эмпирическое правило: всякий раз, когда 1) это самый простой/самый естественный способ решения проблемы и 2) он непреднамеренно не увеличивает асимптотически более высокие затраты во время выполнения или хранения. Это решение нарушает 2), потому что оно копирует каждый список и каждую строку на каждом уровне рекурсии. Но для небольших строк это не имеет значения.
Если вы не используете оператор
return, ничего не возвращается.