[路飞]_前端算法第七十四弹-合法二叉搜索树

108 阅读2分钟

实现一个函数,检查一棵二叉树是否为二叉搜索树。

示例 1:

输入:
    2
   / \
  1   3
输出: true

示例 2:

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

检查一棵二叉树是否为二叉搜索树,首先要知道什么是二叉搜索树

要么是一颗空树,要么其左子节点都小于其根节点,其右子结点都大于其根节点。并且其左右子树也符合该定义。

这个定义就意味着我们需要用到递归函数,最开始可能会想到只要判断左节点小于根节点,右节点大于根节点即可。

var isValidBST = function (root) {
  return bst(root);
};

var bst = function (root) {
  if (root == null)
  return true;
	if(root.val<root.left.val||root.val>root.right.val) return false
	bst(root.left)
	bst(root.right)
}

但是这可能会出现一种情况

    4
   / \
  3   7
 / \
2   5

虽然5大于3,但是5也大于4,而一个合法二叉搜索树5这个位置必须小于4。

所以我们需要设定一个范围。以根节点为例,其左子树的结点应小于根节点,其左子树的右子树的结点值应该在其左子树结点值和根节点的结点值之间。同理根节点的右子树的左子节点的值应该在其根节点和右子结点的值之间。

var isValidBST = function (root) {
  return bst(root, -Infinity, Infinity);
};

var bst = function (root, minVal, maxVal) {
  if (root == null) return true;
  if (root.val >= maxVal || root.val <= minVal) return false;
  return bst(root.left, minVal, root.val) && bst(root.right, root.val, maxVal);
}

我们还可以利用其性质

    4
   / \
  3   7
 / \
2   5

其左子树一定是小于其父节点的。我们递归root.left

while (root) {
      stack.push(root);
      root = root.left
}

我们得到的一定是一个单调递减的数组。而对于其中某个节点的右子结点来说,右子结点的所有值都应该大于该值。并且右子结点的值也符合其左子节点单调递减。

var isValidBST = function (root) {
  let stack = []
  let inorder = -Infinity

  while (stack.length || root !== null) {
    while (root) {
      stack.push(root);
      root = root.left
    }
    root = stack.pop()
    if (root.val <= inorder) return false
    inorder = root.val
    root = root.right
  }
  return true
}