返回

验证二叉搜索树:深入理解BST的性质

后端

LeetCode 上的二叉搜索树(BST)系列之旅,我们已经探讨了插入、搜索和删除操作。现在,是时候深入了解 BST 的一个关键性质——有序性。这正是「验证二叉搜索树」问题所要解决的。

验证二叉搜索树的性质

BST 的有序性体现在两个方面:

  • 左子树上的所有节点值都小于根节点值。
  • 右子树上的所有节点值都大于根节点值。

算法实现

中序遍历

验证 BST 的最简单方法之一是中序遍历。中序遍历将节点值按升序排列,因此如果 BST 有序,则中序遍历结果应该是一个有序序列。

def is_valid_bst(root):
  # 中序遍历结果
  result = []
  
  def traverse(node):
    if not node:
      return
    
    traverse(node.left)
    result.append(node.val)
    traverse(node.right)
  
  traverse(root)
  
  # 检查结果是否有序
  return result == sorted(result)

递归比较

另一种方法是递归比较每个节点与其子节点的值。如果一个节点的值小于其左子节点或大于其右子节点,则表明该 BST 无序。

def is_valid_bst(root):
  # 验证函数
  def validate(node, lower, upper):
    if not node:
      return True
    
    # 当前节点值超出范围
    if node.val <= lower or node.val >= upper:
      return False
    
    # 递归验证子节点
    return validate(node.left, lower, node.val) and validate(node.right, node.val, upper)
  
  # 从最小值和最大值开始验证
  return validate(root, float('-inf'), float('inf'))

优化

最大值和最小值跟踪

在递归比较中,每次调用 validate 函数时,都会更新 lower 和 upper 界限。我们可以优化这个过程,通过在每个节点处跟踪子树的最大值和最小值。这样,在验证该节点的子节点时,我们可以直接使用这些值作为界限。

def is_valid_bst(root):
  # 节点信息(值、最小值、最大值)
  class NodeInfo:
    def __init__(self, val, min, max):
      self.val = val
      self.min = min
      self.max = max
  
  def validate(node):
    if not node:
      return NodeInfo(None, None, None)
    
    # 递归验证子节点
    left_info = validate(node.left)
    right_info = validate(node.right)
    
    # 检查是否有序
    if (left_info.max is None or left_info.max < node.val) and (right_info.min is None or right_info.min > node.val):
      return NodeInfo(node.val, left_info.min or node.val, right_info.max or node.val)
    else:
      return None
  
  # 从根节点开始验证
  return validate(root) is not None

其他优化

  • 使用堆栈或队列进行迭代而不是递归。
  • 利用 BST 的平衡特性,使用分治法。
  • 对于大型数据集,考虑使用并行算法。