【算法】验证二叉搜索树

107 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情

题目

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

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

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

解题思路

非空的二叉搜索树有如下性质:

  1. 非空左子树的所有键值小于其根结点的键值;

  2. 非空右子树的所有键值大于其根结点的键值;

  3. 左右子树均为二叉搜索树

  4. 树中没有键值相等的结点

递归解法

递归求法还是和原先方法一样先制定终止条件。因为搜索树要求的是左右子树的值都是小于或大于其根节点值因此需要特殊判断处理节点值是否超出条件。

  1. 节点值为空表示递归过程结束且满足条件 返回结果是满足条件的。
  2. 然后判断节点的值是否小于最小值,是否大于最大值。若超出则返回结果不满足条件。
  3. 进入递归循环时左边节点需要调整传入的最大值是当前节点值。
  4. 归循环右边节点需要调整传入的最小值是当前节点值。
   public boolean bst(TreeNode root,long min,long max){
        if(root == null) return true;
        if(root.val <= min || root.val >= max) return false;
        return  bst(root.left,min,root.val) && bst(root.right,root.val,max);
    }

    public boolean isValidBST(TreeNode root) {
        return bst(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

迭代解法

迭代算法采用中序遍历实现。遍历从根节点开始,先从左子树最左节点开始处理。

  1. 根节点不为空或者栈不为空时做循环操作。
  2. 先遍历左子树,将当前节点压入栈,直到当前节点无左子树,则弹出栈中节点。
  3. 然后访问节点右子树,从栈中弹出节点和上次弹出节点值做比较,当值大继续操作直到结束;若出现小于或等于时则表示不是二叉搜索树。
   public boolean isValidBST(TreeNode root) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode pre = null;
        while(stack.size() > 0 || root != null){ 
            if(root != null){ 
                stack.add(root); 
                root = root.left; // 左子树节点入栈
            }else{ // 左子树都入栈之后 开始判断右子树的情况
                TreeNode cur = stack.pop();
                // 当前值小于或等于则表示非二叉搜索树
                if(pre != null && cur.val <= pre.val){
                    return false;
                }
                pre = cur;
                root = cur.right;
            }
        }
        return true;
    }
}

参考