LeetCode HOT100 验证二叉搜索树

98. 验证二叉搜索树

本题为 [LeetCode 热题 HOT 100] 中通过率为 36.5% 的题目

难度:【中等】

题目链接:https://leetcode.cn/problems/validate-binary-search-tree/


题目

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

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

  • 节点的左子树只包含 小于 当前节点的数。

  • 节点的右子树只包含 大于 当前节点的数。

  • 所有左子树和右子树自身必须也是二叉搜索树。

示例1:

在这里插入图片描述

输入:root = [2,1,3]
输出:true

示例2:

在这里插入图片描述

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

题解

思路一:中序遍历

看到题目,不难想到二叉搜索树的特性 - 二叉搜索树的中序遍历序列是递增序列

于是我们直接开辟一个集合用来存放中序遍历结果,然后确认他是递增的即可,这个集合可以是队列/栈/List等任何有序集合。

那么就可以写出以下代码(这里使用ArrayList进行存储,由于本思路过于简单,不再进行额外解读):

/**
 * 执行用时:1 ms, 在所有 Java 提交中击败了27.83%的用户
 * 内存消耗:40.7 MB, 在所有 Java 提交中击败了90.34%的用户
 */
class Solution {
    List<Integer> list;

    public boolean isValidBST(TreeNode root) {
        list = new ArrayList<>();
        // 中序遍历
        getMid(root);
        // 确认递增
        int t = list.get(0);
        for (int i = 1; i < list.size(); i++) {
            int e = list.get(i);
            if (e > t) {
                t = e;
            } else {
                return false;
            }
        }
        return true;
    }

    void getMid(TreeNode root) {
        if (root == null)
            return;
        getMid(root.left);
        list.add(root.val);
        getMid(root.right);
    }
}

思路二:递归判断节点

对于递归的解法,仍是逐步引入解读

  1. 用递归的角度去判断二叉搜索树,实际上就是判断每个节点和它的左右子节点是否符合二叉搜索树的条件(不完全如此)
  2. 但是二叉搜索树除了左右子节点的关系之外,还要确保 左子树的最大值 < 右子树的最小值
  3. 由此以来我们需要利用3个参数进行二叉搜索树的判断 -> (当前节点、最大值、最小值)
  4. 除此之外,还需要考虑数据范围 -2147483648 ~ 2147483647

在最初的时候,考虑了很多用int来表示的数据类型,最后在几个特殊用例下总是无法通过,于是乎便偷懒直接用long类型

代码如下:

/**
 * 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
 * 内存消耗:40.7 MB, 在所有 Java 提交中击败了92.50%的用户
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE);
    }

    // 
    public boolean isValid(TreeNode node, long min, long max) {
        // 此处的null表示如果当前节点为“叶子节点”,则直接返回
        if (node == null) {
            return true;
        }
      	// 节点的值不合理
        if (node.val <= min || node.val >= max) {
            return false;
        }
      	// 判断左右子节点
      	// 左子节点的值可以小但不能小于最小值,可以大但不能大于父节点
      	// 右子节点的值可以大但不能大于最大值,可以小但不能小于父节点
        return isValid(node.left, min, node.val) && isValid(node.right, node.val, max);
    }
}

思路三:中序遍历new

本思路原作者:https://leetcode.cn/u/18064109537/

在递归执行每个节点的时候,左子节点不用过多考虑,只需保证右子节点的值小于当前节点即可,此处使用 last 存放当前的节点的值

代码如下:

/**
 * 执行用时:0 ms, 在所有 Java 提交中击败了100.00%的用户
 * 内存消耗:40.8 MB, 在所有 Java 提交中击败了79.01%的用户
 */
class Solution {
    Integer last = null;

    public boolean isValidBST(TreeNode root) {
      	// 叶子节点
        if (root == null) {
            return true;
        }
      	// 左子节点不合理 -> 退出
        if (!isValidBST(root.left)) {
            return false;
        }
      	// last有值,那么这个值必须小于右子节点,否则退出
        if (last != null && last >= root.val) {
            return false;
        }
      	// 在进行右子节点判断之前需要重新赋值last
        last = root.val;
        if (!isValidBST(root.right)) {
            return false;
        }
        return true;
    }
}

如果有更好的解题思路欢迎留言评论区

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值