Максимальная рекурсия в рекурсивной функции LCS
Я пытаюсь выполнить функцию LCS, которая использует рекурсию, чтобы дать мне количество позиций, которые действительны LCS, наряду с местом LCS, изображенным здесь:
input: LCS("smile", "tile")
output: [3, "##ile", "#ile"]
Всякий раз, когда я пытаюсь выполнить его, он говорит мне, что есть ошибка рекурсии, как показано ниже:
RecursionError: maximum recursion depth exceeded in comparison
Что не так с моим кодом? Я попытался заменить области, где LCS не применялся через рекурсию, но где функция превышает ее глубину?
def LCS(s1, s2):
if s1 == "" or s2 == "":
return 0
else:
if s1[0] == s2[0]:
s1 = s1 + s1[0]
s2 = s2 + s2[0]
count = 1 + LCS(s1[1:], s2[1:])
else:
s1 = s1 + '#'
count = max(LCS(s1, s2[1:]), LCS(s1[1:], s2))
array = [count] + [s1] + [s2]
print(array)
3 ответа
Как утверждают другие, вы добавляете символ в строковую переменную и отбираете его в следующем рекурсивном вызове. Таким образом, всегда будут рекурсивные вызовы со строкой, которая имеет начальную длину, что приводит к бесконечной рекурсии.
И при ближайшем рассмотрении это не имеет смысла:
if s1[0] == s2[0]:
s1 = s1 + s1[0]
Здесь вы снова добавляете первый символ в конец строки. Это не может быть правдой.
Также функция имеет возможность вернуть только 0 (или None
), но не более того. Это также не может быть правдой. Что бы ни делала функция, она всегда должна возвращать значение.
Поскольку вы заинтересованы в подсчете совпадающих символов и #
заполненные версии обеих исходных строк, вы можете позволить вашей функции возвращать три значения (список) вместо одного.
Затем код можно заставить работать так:
def LCS(s1, s2):
if s1 == "" or s2 == "":
return 0, '#' * len(s1), '#' * len(s2)
else:
if s1[0] == s2[0]:
count, r1, r2 = LCS(s1[1:], s2[1:])
return count+1, s1[0] + r1, s2[0] + r2
else:
count1, r11, r12 = LCS(s1, s2[1:])
count2, r21, r22 = LCS(s1[1:], s2)
if count2 > count1:
return count2, '#' + r21, r22
else:
return count1, r11, '#' + r12
print (LCS ('smile', 'tile'))
Выход:
(3, '##ile', '#ile')
Смотрите это запустить на repl.it.
В вашем первом рекурсивном вызове (count = 1 + LCS(s1[1:], s2[1:])
), так как вы только что добавили элемент в конец каждого из s1
а также s2
размеры передаваемых строк такие же, как в вызове, поэтому вы не продвигаетесь к завершению
Внутри max
Второй рекурсивный вызов имеет ту же проблему: вы добавили элемент s1
Таким образом, размеры передаваемой строки такие же, как в вызове.
Я не совсем понимаю вашу логику: на каждой итерации вы либо перемещаете первый символ в конец строки, либо отбрасываете его и добавляете знак #. Единственный шаг сокращения в этом - сокращение s2 в нижней ветви, но вы попадете в бесконечную рекурсию, прежде чем доберетесь туда. Я добавил простую трассировку в начало процедуры:
def LCS(s1, s2):
print("ENTER s1=", s1, "\ts2=", s2)
Вот как это застревает:
ENTER s1= smile s2= tile
ENTER s1= smile# s2= ile
ENTER s1= smile## s2= le
ENTER s1= smile### s2= e
ENTER s1= smile#### s2=
ENTER s1= mile#### s2= e
ENTER s1= mile##### s2=
ENTER s1= ile##### s2= e
ENTER s1= ile###### s2=
ENTER s1= le###### s2= e
ENTER s1= le####### s2=
ENTER s1= e####### s2= e
ENTER s1= #######e s2= e
ENTER s1= #######e# s2=
ENTER s1= ######e# s2= e
ENTER s1= ######e## s2=
ENTER s1= #####e## s2= e
ENTER s1= #####e### s2=
ENTER s1= ####e### s2= e
ENTER s1= ####e#### s2=
ENTER s1= ###e#### s2= e
ENTER s1= ###e##### s2=
ENTER s1= ##e##### s2= e
ENTER s1= ##e###### s2=
ENTER s1= #e###### s2= e
ENTER s1= #e####### s2=
ENTER s1= e####### s2= e
ENTER s1= #######e s2= e
Когда вы терпите неудачу в прогоне, вам нужно сбросить s2 к его первоначальному значению. Ваш текущий код резервируется с еще одним символом в каждой строке, оставляя s2 постоянно подпрыгивая между его последним символом и NULL.