LeetCode - 98. Validate Binary Search Tree(判断是不是一颗二叉搜索树以及判断完全二叉树)

33 篇文章 0 订阅

LeetCode - 98. Validate Binary Search Tree(判断是不是一颗二叉搜索树以及判断完全二叉树)

  • LeetCode - 98. Validate Binary Search Tree (判断一颗二叉树是不是一颗二叉搜索树)
  • 判断一颗二叉树是不是一颗完全二叉树
  • 完整测试代码

LeetCode - 98. Validate Binary Search Tree (判断一颗二叉树是不是一颗二叉搜索树)

题目链接
题目在这里插入图片描述

首先要知道什么是二叉搜索树(二叉排序树)(二叉查找树) :

  • 任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 任意节点的左、右子树也分别为二叉搜索树;
  • 一般没有键值相等的节点。

例如下面的树就是一颗二叉搜索树 :
这里写图片描述
怎么判断一颗二叉树是不是搜索二叉树呢? 其实很简单,只要这颗二叉树的中序遍历的顺序是升序的,那么就是一颗二叉搜索树,因为中序遍历的顺序是 左->中->右 ,所以当中序遍历升序的时候,就有左<中<右,所以就可以判断。

class Solution {
    public boolean isValidBST(TreeNode root) {
        if(root == null)
            return true;
        Stack<TreeNode>stack = new Stack<>();
        TreeNode cur = root;
        TreeNode pre = null;
        while(!stack.isEmpty() || cur != null){
            if(cur != null){
                stack.push(cur);
                cur = cur.left;
            }else {
                cur = stack.pop();
                if(pre != null && cur.val <= pre.val)
                    return false;
                pre = cur;
                cur = cur.right;
            }
        }
        return true;
    }
}

代码中使用的是非递归的中序遍历,不懂的可以看这个博客
当然也可以使用中序的递归,记录一个全局的pre变量:

class Solution {
    private TreeNode pre;
    public boolean isValidBST(TreeNode root) {
        if(root == null)
            return true;
        pre = null;
        return inOrder(root);
    }
    
    private boolean inOrder(TreeNode node){
        if(node == null)
            return true;
        if(!inOrder(node.left))
            return false;
        if(pre != null && node.val <= pre.val)
            return false;
        pre = node;
        if(!inOrder(node.right))
            return false;
        return true;
    }
}

还有一种解法就是利用左右两边的minmax:

  • 递归函数有三个值,当前结点node,node在中序遍历中的前一个结点pre的值minnode在中序遍历中的后一个节点next的值max
  • 在递归的过程中,先判断当前的结点是否满足min < node.val && node.val < max,如果不满足就返回false
  • 判断完之后,还要判断孩子是否满足;
class Solution {
    public boolean isValidBST(TreeNode root) {
        if(root == null)
            return true;
        return helper(root,null,null);
    }
    
    //min、max 也可以看做是 pre、next  就是root的前一个、后一个
    private boolean helper(TreeNode node,Integer min,Integer max){
        if(node == null)
            return true;
        //先判断自己
        if( (min != null && node.val <= min) || (max != null && node.val >= max) )
           return false;
        // 判断左孩子
        if( !helper(node.left,min,node.val))
           return false;
        //判断右孩子
        if( !helper(node.right,node.val,max))
           return false;
        return true;
    }
}

这里还需要注意当node = Integer.MIN_VALUE或者Integer.MAX_VALUE这两个值的影响。


判断一颗二叉树是不是一颗完全二叉树

首先知道什么是完全二叉树:

  • 完全二叉树是由满二叉树(一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。即如果一个二叉树的层数为K,且结点总数是(2k) -1 ,则它就是满二叉树)而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1n的结点一一对应时称之为完全二叉树。
  • 若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1)的结点数都达到最大个数,第h 层所有的结点都连续集中在最左边,这就是完全二叉树。
  • 或者说: 一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。

那么如何判断一棵二叉树是否为完全二叉树呢? 按照下面的标准 :

  • 按照层次遍历的顺序遍历二叉树,每一层从左到右;
  • 如果当前结点有右孩子但没有左孩子,直接返回false
  • 如果当前结点不是左右孩子都全(包括两种情况),那之后的结点必须都为叶节点,否则返回false
  • 遍历过程中如果没有返回false,就返回true

怎么理解上面的过程呢?

  • 如果当前结点有右孩子但没有左孩子,按照完全二叉树的定义,不符合,如下面的情况:
    这里写图片描述
  • 当前结点不是左右孩子都全包括两种情况(前面的那种已经判断了),第一,有左孩子没有右孩子,那么后面的结点必须全部为叶子结点,如果出现非叶子结点,就返回false。如下:
    这里写图片描述
    第二种情况就是左右孩子都没有,也要开启判断后面的结点必须全部都是叶子结点的过程,如下:
    这里写图片描述

所以综上,我们就可以写出代码,使用层次遍历,用一个bool型变量leaf记录是否遇到了左右孩子是不是不全的情况(这时就开始判断后面的结点是不是叶子结点),代码如下 :

    //判断一棵二叉树是不是完全二叉树
    static boolean isCBT(TreeNode root){
        if(root == null)
            return true;
        Queue<TreeNode>queue = new LinkedList<>();
        boolean leaf = false; //如果碰到了 某个结点孩子不全就开始 判断是不是叶子这个过程
        queue.add(root);
        TreeNode top = null,L = null,R = null;
        while(!queue.isEmpty()){
            top = queue.poll();
            L = top.left;  R = top.right;
            //第一种情况
            if((R != null && L == null))
                return false;
            //第二种情况  开启了判断叶子的过程 而且又不是叶子 就返回false
            if(leaf && (L != null || R != null)) //以后的结点必须是 左右孩子都是null
                return false;

            if(L != null)
                queue.add(L);

            //准确的说是 只要孩子不全就开启leaf,
            //但是前面已经否定了有右无左的情况,这里只要判断一下右孩子是不是为空就可以了(如果为空就开启leaf)
            if(R != null)
                queue.add(R);
            else
                leaf = true;
        }
        return true;
    }

完整测试代码(上面的例子)

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/**
 * 判断一棵二叉树是否为搜索二叉树
 * 判断一棵二叉树是否为完全二叉树
 */
public class IsBSTAndCBT {

    static class TreeNode{
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int value) {
            this.val = value;
        }
    }

    static boolean isBST(TreeNode root){
        if(root == null)
            return true;
        Stack<TreeNode>stack = new Stack<>();
        TreeNode cur = root;
        TreeNode pre = null;
        while(!stack.isEmpty() || cur != null){
            if(cur != null){
                stack.push(cur);
                cur = cur.left;
            }else {
                cur = stack.pop();
                if(pre != null && cur.val <= pre.val)
                    return false;
                pre = cur;
                cur = cur.right;
            }
        }
        return true;
    }

    //判断一棵二叉树是不是完全二叉树
    static boolean isCBT(TreeNode root){
        if(root == null)
            return true;
        Queue<TreeNode>queue = new LinkedList<>();
        boolean leaf = false; //如果碰到了 某个结点孩子不全就开始 判断是不是叶子这个过程
        queue.add(root);
        TreeNode top = null,L = null,R = null;
        while(!queue.isEmpty()){
            top = queue.poll();
            L = top.left;  R = top.right;
            //第一种情况
            if((R != null && L == null))
                return false;
            //第二种情况  开启了判断叶子的过程 而且又不是叶子 就返回false
            if(leaf && (L != null || R != null)) //以后的结点必须是 左右孩子都是null
                return false;

            if(L != null)
                queue.add(L);

            //准确的说是 只要孩子不全就开启leaf,
            //但是前面已经否定了有右无左的情况,这里只要判断一下右孩子是不是为空就可以了(如果为空就开启leaf)
            if(R != null)
                queue.add(R);
            else
                leaf = true;
        }
        return true;
    }


    public static void main(String[] args) {

        System.out.println("===============test for BST================");
        System.out.println("---------test1--------------");
        TreeNode head = new TreeNode(1);
        System.out.println(isBST(head));//true

        System.out.println("---------test2--------------");
        head = new TreeNode(2);
        head.left = new TreeNode(1);
        head.right = new TreeNode(3);
        System.out.println(isBST(head));//true

        System.out.println("---------test3--------------");
        head = new TreeNode(2);
        head.left = new TreeNode(1);
        head.right = new TreeNode(0);
        System.out.println(isBST(head));//false

        System.out.println("---------test4(for example)--------------");
        head = new TreeNode(5);
        head.left = new TreeNode(3);
        head.left.left = new TreeNode(2);
        head.left.right = new TreeNode(4);
        head.left.left.left = new TreeNode(1);
        head.right = new TreeNode(8);
        head.right.left = new TreeNode(6);
        head.right.left.right = new TreeNode(7);
        head.right.right = new TreeNode(10);
        head.right.right.left = new TreeNode(9);
        System.out.println(isBST(head));

        System.out.println();

        System.out.println("===============test for CBT================");
        head = new TreeNode(1);
        head.left = new TreeNode(2);
        head.left.left = new TreeNode(4);
        head.left.right = new TreeNode(5);
        head.left.left.left = new TreeNode(8);
        head.left.left.right = new TreeNode(9);
        head.left.right.right = new TreeNode(10); //false
        head.right = new TreeNode(3);
        head.right.left = new TreeNode(6);
        head.right.right = new TreeNode(7);
        System.out.println(isCBT(head));

        head = new TreeNode(1);
        head.left = new TreeNode(2);
        head.left.left = new TreeNode(4);
        head.left.right = new TreeNode(5);
        head.left.left.left = new TreeNode(8);
        head.left.left.right = new TreeNode(9);
        head.left.right.left = new TreeNode(10); //true
        head.right = new TreeNode(3);
        head.right.left = new TreeNode(6);
        head.right.right = new TreeNode(7);
        System.out.println(isCBT(head));

        head = new TreeNode(1);
        head.left = new TreeNode(2);
        head.left.left = new TreeNode(4);
        head.left.right = new TreeNode(5);
        head.left.left.left = new TreeNode(8);
        head.left.left.right = new TreeNode(9);
       // head.left.right.left = new TreeNode(10); //true
        head.right = new TreeNode(3);
        head.right.left = new TreeNode(6);
        head.right.right = new TreeNode(7);
        System.out.println(isCBT(head));
    }
}

运行结果
这里写图片描述


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值