这个递归如何在python中工作?

时间:2013-09-19 15:08:18

标签: python recursion python-3.x palindrome

我在几个小时前观看了一段关于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]如果你认为你知道任何有助于简化递归的好地方随时分享他们。提前谢谢。

5 个答案:

答案 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 evaluationBlender在他的帖子中就是一个很好的例子。

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