LeetCode探索(28):98-验证二叉搜索树

232 阅读1分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。

题目

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

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

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

示例 1:

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

示例 2:

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

提示:

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

思考

这是二叉树相关的一道题目,难度中等。

有效的二叉搜索树,需满足左子树节点的值 < 根节点的值 < 右子树节点的值,我们可以发现,这不正是中序遍历的过程吗?那么,我们可以考虑通过中序遍历解决该问题。即每次遍历二叉树的节点时,把根节点存入栈函数中,并找到最左子树的节点,然后开始判断。如果所有的根节点均需要满足上面的条件,则为有效的二叉搜索树。

此外,我们可以通过递归的方法,借助一个递归函数helper(root, lower, upper),判断子树中所有节点的值是否都在 (lower, upper) 的范围内。

解答

方法一:中序遍历

var isValidBST = function(root) {
  let stack = []
  let inorder = -Infinity
  while (stack.length || root) {
    // while循环,找到数值最小的叶子节点,存入各个根节点
    while (root) {
      stack.push(root)
      root = root.left
    }
    // 删除并返回数组的最后一个元素
    root = stack.pop()
    // 如果中序遍历得到的节点的值小于等于前一个 inorder,说明不是二叉搜索树
    if (root.val <= inorder) {
      return false
    }
    // 更新inorder
    inorder = root.val
    // 更新root:中序遍历是左根右,所以这里赋值为root.right
    root = root.right
  }
  return true
}

复杂度分析

  • 时间复杂度 : O(n),其中 n 为二叉树的节点个数。二叉树的每个节点最多被访问一次。
  • 空间复杂度 : O(n),其中 n 为二叉树的节点个数。栈最多存储 n 个节点,因此需要额外的 O(n) 的空间。

方法二:递归

const helper = (root, lower, upper) => {
  if (!root) {
    return true
  }
  if (root.val <= lower || root.val >= upper) {
    return false
  }
  return helper(root.left, lower, root.val) && helper(root.right, root.val, upper)
}
var isValidBST = function(root) {
  return helper(root, -Infinity, Infinity)
}

复杂度分析

  • 时间复杂度 : O(n),其中 n 为二叉树的节点个数。在递归调用的时候二叉树的每个节点最多被访问一次。
  • 空间复杂度 : O(n),其中 n 为二叉树的节点个数。

参考