leetcode刷题(21)——98. 验证二叉搜索树

给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

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

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

示例 2:

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

坑爹之处:乍一看,这是一个平凡的问题。只需要遍历整棵树,检查 node.right.val > node.val 和
node.left.val < node.val 对每个结点是否成立。
于是我做了如下的写法:

class Solution {

        public boolean isValidBST(TreeNode root) {
            if (root == null) {
                return true;
            }
            if (isValid(root)) {
                return isValidBST(root.left) && isValidBST(root.right);
            }
            return false;
        }

        public boolean isValid(TreeNode root) {
            if (root.left == null && root.right == null) {
                return true;
            } else if (root.left == null) {
                if (root.right.val > root.val) {
                    return true;
                }
            } else if (root.right == null) {
                if (root.left.val < root.val) {
                    return true;
                }
            } else {
                return root.val < root.right.val && root.val > root.left.val;
            }
            return false;
        }
    }

**问题是,这种方法并不总是正确。不仅右子结点要大于该节点,整个右子树的元素都应该大于该节点。**例如:
这意味着我们需要在遍历树的同时保留结点的上界与下界,在比较时不仅比较子结点的值,也要与上下界比较。

方法一: 递归

class Solution {
    
    public boolean isValidBST(TreeNode root) {
         
        return isValid(root,null,null);
    }
    
    public boolean isValid(TreeNode root,Integer lower,Integer upper){
        if (root == null) return true;
        int value = root.val;
        if(lower!=null&&value<=lower){
            return false;
        }
        if(upper!=null&&value>=upper){
            return false;
        }
        if(!isValid(root.right,value,upper)){
            return false;
        }
        if(!isValid(root.left,lower,value)){
            return false;
        }
        return true;
    }

方法二:中序遍历
左子树 -> 结点 -> 右子树的顺序。
左子树 -> 结点 -> 右子树 意味着对于二叉搜索树而言,每个元素都应该比下一个元素小。

因此,具有 {O}(N)O(N) 时间复杂度与 {O}(N)O(N) 空间复杂度的算法十分简单:

计算中序遍历列表 inorder.

检查 inorder中的每个元素是否小于下一个。

事实上不需要。因此,我们可以将步骤整合并复用空间。

class Solution {
  public boolean isValidBST(TreeNode root) {
    Stack<TreeNode> stack = new Stack();
    double inorder = - Double.MAX_VALUE;

    while (!stack.isEmpty() || root != null) {
      while (root != null) {
        stack.push(root);
        root = root.left;
      }
      root = stack.pop();
      // If next element in inorder traversal
      // is smaller than the previous one
      // that's not BST.
      if (root.val <= inorder) return false;
      inorder = root.val;
      root = root.right;
    }
    return true;
  }
}
发布了204 篇原创文章 · 获赞 684 · 访问量 89万+

猜你喜欢

转载自blog.csdn.net/u012124438/article/details/102691910
今日推荐