Skip to content

98. 验证二叉搜索树

题目

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

img

输入:root = [2,1,3]
输出:true

示例 2:

img

输入:root = [5,1,4,null,null,3,6]
输出:false
解释:根节点的值是 5 ,但是右子节点的值是 4 。

提示:

  • 树中节点数目范围在[1, 10^4]
  • -2^31 <= Node.val <= 2^31 - 1

解答

思路:前序遍历

image-20240118203217457

二叉搜索树:

  • 左子树都小于根节点:左子树的值区间为 (-inf, 5)
  • 右子树都大于根节点:右子树的值区间为 (5, +inf)
  • 对于 4 而言,它的区间经过累计计算后为 (2, 5),也就是祖先的最小值和最大值

递归时除了传入结点 node,还需要传入开区间的范围:对于每个节点值,先判断它的 val 是否在开区间内,然后再往下递归:往左递归就更新开区间的右边界值,往右递归就更新开区间的左边界值。这种先访问节点值,再递归左右子树的做法叫做 前序遍历

注意:根节点传入 (-inf, inf) 即可。

代码

Python 代码

python
class Solution:
    def isValidBST(self, root: Optional[TreeNode], left=-inf, right=inf) -> bool:
        if root is None:
            return True
        
        x = root.val

        return left < x < right and \
                self.isValidBST(root.left, left, x) and \
                self.isValidBST(root.right, x, right)

思路:中序遍历

如果按照先遍历左子树,再遍历根节点,最后遍历右子树的方式,我们遍历 二叉平衡树 就会得到一个严格递增的数组。可以用数学归纳法证明(因为 BST 始终有左子树 < 根节点 < 右子树)。

如何验证数组是严格递增的?比较相邻的数字即可。在二叉树中,比较当前的节点值是否大于上一个节点值,然后把节点值记录下来方便后续比较。第一个节点没有前驱,可以将其初始化为 -inf

代码

Python 代码

python
class Solution:
    pre = -inf

    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if root is None:
            return True
        
        if not self.isValidBST(root.left):
            return False
        
        if root.val <= self.pre:
            return False
        
        self.pre = root.val

        return self.isValidBST(root.right)

思路:后序遍历

我们还可以把节点值的范围往上传:

image-20240118205036708

以 5 为例,它左子树的范围是 [1, 4],右子树的范围是 [6, 6]。那么由于 5 大于左边的最大值,小于右边的最小值,因此 5 这个值是合理的。这种做法需要先遍历左右子树,得到范围,再判断根节点和范围的关系,被称为 后序遍历

注意:并不是左边只需要返回最大值才行,左子树的最大值用于和根节点比较,左子树的最小值用于范围框定,右子树同理。最小值和最大值都需要返回。递归到空节点时,可以返回 (inf, -inf),这样通过空节点对于 BST 的判断就一定不成立。

最后如果返回的结果是 (-inf, inf),说明不是 BST。

代码

Python 代码

python
class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        def f(node):
            if node is None:
                return inf, -inf
            
            l_min, l_max = f(node.left)
            r_min, r_max = f(node.right)

            x = node.val

            if x <= l_max or x >= r_min: # (inf, -inf) 一定保证它不成立
                return -inf, inf
            
            return min(l_min, x), max(r_max, x)
        
        return f(root)[1] != inf

Released under the MIT License.