我在几个小时前观看了一段关于python递归的视频,然后重新创建了在视频中制作的程序,因此它在我的Python版本中运行。代码有效,但有一点我完全不了解它正在做什么。
def lower(s):
s = s.lower()
return s
def isPal(s):
if len(s) <= 1:
return True
else:
return s[0] == s[-1] and isPal(s[1:-1])
def isPalindrome(s):
if isPal(lower(s)) == True:
print("{0} is a palindrome".format(s))
我遇到问题的部分是
return s[0] == s[-1] and isPal(s[1:-1])
我想知道为什么他们被退回,为什么它是[1:-1]而不是s [0:-1]如果你认为你知道任何有助于简化递归的好地方随时分享他们。提前谢谢。
答案 0 :(得分:5)
为什么它是[1:-1]而不是s [0:-1]
s[1:-1]
返回s
,第一个和最后一个元素被删除。 s[0:-1]
返回s
,只删除最后一个元素。
你需要切断两端以保持回文性质(如果它是回文),即与中间等距的元素是相同的。如果你只切断一端,你移动中间,这将(在一般情况下)破坏该不变量。
这是自我递归的核心:你做了一件事,然后你委托一个具有相同属性的简单案例。
为什么返回s [0] == s [-1]和isPal(s [1:-1])
这是返回的,因为它首先检查第一个和最后一个元素是否具有回文属性(如上所述)并且下一个“图层”也具有该属性。如果外部对不相等则不是回文,并且将返回False
;如果为true,则执行递归步骤,如果为True,则表达式返回True
。
答案 1 :(得分:3)
想象一下,你有'kayak'这个词
该程序将查看是否:
'k' == 'k'
如果是,程序将使用:'aya'
然后程序将查看是否'a' == 'a'
如果是,程序将使用'y'
调用该函数
然后它只有一个字母,所以程序返回True
答案 2 :(得分:3)
这就是魔术发生的地方:
return (s[0] == s[-1]) and isPal(s[1:-1])
(我添加了括号,因此您对运算符优先级非常清楚)。重要的是要知道Python AND语句将评估第一个参数,并且只有当它是True
时,它才会评估第二个参数。如果第一个是False
,那么它会立即返回False
而不会调用isPal()
。这称为short-circuit evaluation。 Blender在他的帖子中就是一个很好的例子。
s[0]
是字符串中的第一个字母,s[-1]
是sting中的最后一个字母。首先,我们检查第一个和最后一个字母是否相同。如果它们不同,则字符串无法成为回文。如果它们是相同的,我们可以忽略它们并移动到字符串的内部部分。
s[1:-1]
修剪掉第一个和最后一个字母,然后将其传递给isPal()
函数,这恰好是我们当前的函数 - 这称为递归。当我们再次'进入'函数时,会创建一个新的堆栈,创建新的局部变量,并且该函数的输入参数将与前一次调用中的参数不同。
我们继续检查第一个和最后一个字母,并一直递归到单词的中心。此时还剩下1或0个字符,如果我们到目前为止,我们知道我们找到了一个回文。
当我们从最后的内部返回时,调用isPal()
返回值(True
如果已找到回文)被传递给调用函数,然后调用函数将其返回给它的调用函数等等,直到最后的'outside'isPal()
函数将结果返回给初始调用者。我们将此过程称为“展开堆栈”。
以下是一个例子:
s = 'racecar'
s[0] == s[-1] # True - both letters are 'r'
s = s[1:-1] # s becomes 'aceca'
s[0] == s[-1] # True - both letters are 'a'
s = s[1:-1] # s becomes 'cec'
s[0] == s[-1] # True - both letters are 'c'
s = s[1:-1] # s becomes 'e'
len(s) <= 1 # This statement is now True, so the stack will start to unwind
视觉上,这些电话会是这样的:
'racecar' ---------
|
V 'aceca'
True <--- isPal( ) ----
^ |
True | V 'cec'
---- isPal( ) ----
^ |
True | V 'e'
---- isPal( ) ----
^ |
True | V
---- isPal( ) # We get all the way down here,
# and then we start to return
如果我们没有回文,就会发生这种情况:
'race2car' --------
|
V 'ace2ca'
False <--- isPal( ) ----
^ |
False | V 'ce2c'
---- isPal( ) ----
^ |
False | V 'e2'
---- isPal( ) ----
^ |
False | V
---- isPal( ) # Here the outer two letters
# do not match, so we start to
# return False
答案 3 :(得分:1)
你正在检查s
的第一个和最后一个是否相同,所以一旦你这样做,你将它们切掉并通过返回,递归部分检查下一个和最后一个是否相同继续将结果加在一起,直到s中有1个或更少的字母。然后它返回到目前为止收集的内容和True。
在print(s)
之前的行上添加if len(s) <= 1:
或在print(s[0] == s[-1] and isPal(s[1:-1]))
之后添加else:
可以帮助您更多地了解递归。
答案 4 :(得分:0)
该步骤使用短路逻辑AND,因此它的行为如下:
if s[0] != s[-1]:
return False
else:
return isPal(s[1:-1])
对于s[1:-1]
,您将第一个和最后一个字符与s[0] != s[-1]
进行比较,因此s[1:-1]
只删除第一个和最后一个字符,并将结果字符串传递回isPal