【问题标题】:Validating a BST algorithm验证 BST 算法
【发布时间】:2022-11-24 23:20:07
【问题描述】:

我正在尝试解决一个 leetcode 问题,但我的代码遇到了问题。 我想要的是 prev 存储前一个节点的值,但是当我运行递归代码时,prev 的值总是变为 None。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right

class Solution:
    
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True
        prev = None
        if root:
            if not self.isValidBST(root.left):
                return False
            
            if  prev is not None and prev >= root.val:
                return False
            prev = root.val
            return self.isValidBST(root.right)

你能解释一下为什么这段代码会失败,特别是为什么每次递归调用时 prev 的值总是变成 None

【问题讨论】:

    标签: python python-3.x tree binary-search-tree dsa


    【解决方案1】:

    你能解释一下为什么这段代码失败了,尤其是为什么 prev 的值在每次递归调用中总是变为 None

    变量prev是每个帧的局部变量(递归/函数调用).在每次递归过程中,您将其初始化为 None。这会导致您的代码永远不会达到条件 if prev is not None and prev >= root.val:,因为每次评估时 prev 始终是 None

    我认为这个回复可能对你有价值:What is the relation between stack frame and a scope?

    还有这个(它来自 python1 文档,但仍然有效):https://understanding-recursion.readthedocs.io

    【讨论】:

      【解决方案2】:

      该问题有两个原因:

      • prev 是一个本地名称,无论在递归调用中 prev 发生什么,它都不会影响调用方的 prev 的值,因为这是一个不同的名称。具体来说,条件if prev is not None永远不会为真; prev 仍然是 None
      • 即使您以某种方式使 prev 成为非本地名称,以便所有递归调用都可以访问相同的prev, these calls (except for the base case), all set previs back toNone. But this is undesired: you should maintain the previous value, except for the case where the top-level (first) call is made: only then should prevbe initialised toNone`。

      您可以通过将 prev 定义为全局变量或更好地定义为 self 的属性来解决此问题。这样,递归过程将使用一个prev

      由于您只需要将此 prev 初始化为 None 一次,但有递归调用,因此您应该将初始调用与递归调用分开,并仅在初始调用中执行该初始化。为此,您可以将该函数分成两个函数:主要函数将执行初始化并调用另一个递归函数:

      class Solution:
          def isValidBSTHelper(self, root: Optional[TreeNode]) -> bool:
              if not root:
                  return True
              if not self.isValidBSTHelper(root.left):
                  return False
              if self.prev is not None and self.prev >= root.val:
                  return False
              self.prev = root.val
              return self.isValidBSTHelper(root.right)
      
          def isValidBST(self, root: Optional[TreeNode]) -> bool:
              self.prev = None  # Attribute has larger scope
              return self.isValidBSTHelper(root)
      

      您还可以使用具有递归部分的生成器进行中序遍历,然后遍历该迭代器的值并比较它们:

      class Solution:
          def inorder(self, root: Optional[TreeNode]):
              if root:
                  yield from self.inorder(root.left)
                  yield root.val
                  yield from self.inorder(root.right)
          
          def isValidBST(self, root: Optional[TreeNode]) -> bool:
              values = self.inorder(root)
              prev = next(values, None) # get first value and advance
              for val in values:
                  if prev >= val:
                      return False
                  prev = val
              return True
      

      或者您可以启动两次中序迭代,一步不同,并在 isValidBST 中使用 zipinorder 函数保持不变):

          def isValidBST(self, root: Optional[TreeNode]) -> bool:
              previous = self.inorder(root)
              values = self.inorder(root)
              next(values, None) # move one iterator one step forward
              return all(a < b for a, b in zip(previous, values)) # all pairs must be in order
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-14
        • 1970-01-01
        • 2011-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-22
        • 2011-05-09
        相关资源
        最近更新 更多