验证二叉搜索树

题目:

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

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

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

目录

解法一:中序遍历

解法二 :递归法


二叉搜索树性质

  1. 如果该二叉树的左子树不为空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 它的左右子树也为二叉搜索树。

 根据二叉搜索树的性质,如是中序遍历二叉搜索树的话,我们将得到一个升序序列。我们可以根据这个特性来尝试解决这道题目:

解法一:中序遍历(自下而上判断)

我们将所给的二叉搜索树中序遍历,判断得到的序列是不是严格的升序序列。

代码如下:

class Solution {
    ArrayList<Integer> list = new ArrayList<Integer>();
    public boolean isValidBST(TreeNode root) {
        //中序遍历
        inordered(root);
        //判断list是不是严格升序
        for(int i = 0; i < list.size() - 1; i++){
           if(list.get(i) >= list.get(i + 1)){
               return false;
            }
        }
        return true;
    }
    //中序遍历该二叉搜索树
    public void inordered(TreeNode root){
        if(root == null){
            return;
        }
        inordered(root.left);
        list.add(root.val);
        inordered(root.right);

    }

        这种解法有点傻白甜,查看了一些大神解法后,用同样的思路进行代码优化:可以在中序遍历该树的同时,用当前与中序遍历的前一个节点进行比较,若是当前节点值小于前一个节点,则不满足升序,直接返回false。

尝试代码:

class Solution {
   long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root == null){
            return true;
        }
         //递归左子树
        isValidBST(root.left);
        //判断当前节点值是否小于前一个节点
        if(root.val <= pre){
            return false;
        }    
        //将当前节点值赋给pre,与下一个节点进行比较
        pre = root.val;
        //
        return isValidBST(root.right);
    
    }
}

提交以后发现有bug,经过调试,发现问题所在:

        当root.left > pre,返回 false 后,我们想要的结果是直接结束递归,将false返回即可。 但在对root.left 递归结束后回溯的过程中,上述代码返回false后,只是结束了当前节点的右节点的递归,待回溯下一次root.left的时候,并不能确保右节点不进行递归,这样就会对结果false进行覆盖,相当于上述程序对是否是二叉搜索树的判断结果完全由右树决定。

        解决bug:

        我们已经知道之所以false被覆盖,是因为发现问题节点后没有对后续右节点的递归进行截断处理。我们可以对每次左树递归的回溯结果保留,进行判断,如果为false,则不用执行下面代码(包括对右节点的递归)。

最终代码:

class Solution {
    long pre = Long.MIN_VALUE;
    public boolean isValidBST(TreeNode root) {
        if(root == null){
            return true;
        }
        //处理:对每次递归结果进行判断,如果为false,则直接返回,进行下一次回溯,不用执行下面代码
        if(!isValidBST(root.left)){
            return false;
        }
        
        if(root.val <= pre){
            return false;
        }
        pre = root.val;
        return isValidBST(root.right);
    }
}

解法二 :DFS(自上而下判断)

利用二叉搜索树的性质1和性质2,我们可以构造递归函数来判断当前节点值是否大于左子树,小于右子树,isValidBST(root , l ,r),判断root.val是否在开区间(l , r)之间。

代码实现:

class Solution {
    
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
       
    }
    
    public boolean isValidBST(TreeNode root,long lower,long upper){
        if(root == null){
            return true;
        }
        //判断root.val是否在(lower,upper)之间
        if(root.val <= lower || root.val >= upper){
            return false;
        }
        //左右子树同时满足性质1,2
        return isValidBST(root.left,lower,root.val) && isValidBST(root.right,root.val,upper);
    }
}

等价写法:

class Solution {
    
    public boolean isValidBST(TreeNode root) {
        return isValidBST(root,Long.MIN_VALUE,Long.MAX_VALUE);
       
    }
    
    public boolean isValidBST(TreeNode root,long lower,long upper){
        if(root == null){
            return true;
        }
        //判断root.val是否在(lower,upper)之间
        if(root.val <= lower || root.val >= upper){
            return false;
        }
        //对左子树结果进行判断
        if(!isValidBST(root.left,lower,root.val)){
            return false;
        }
        //若左子树返回true,结果就由右子树确定
        return isValidBST(root.right,root.val,upper);
    }
}

 上述用long而不用int,是为了扩大节点值的范围。若使用int,如果测试用例的节点值超出int的范围也会报错,为了避免,我们使用long。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值