【LeetCode】验证二叉搜索树 [M]

news2024/11/18 0:28:23

98. 验证二叉搜索树 - 力扣(LeetCode)

一、题目

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

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

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

示例 1:

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

示例 2:

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

提示:

  • 树中节点数目范围在[1, 104] 内
  • -231 <= Node.val <= 231 - 1

二、代码

方法一:二叉树递归

这道题也是很典型的递归,记住递归的三要素。

这道题主要是要理解好搜索二叉树的定义。要记住搜索二叉树是节点的左子树上的所有节点一定小于该节点,节点的右子树上的所有节点一定大于该节点。只要知道了这个性质,这道题就好做了。

递归的思路就是保证左右子树都是搜索二叉树,并且当前节点比其左子树的最大值大,比其右子树的最小值小,只要满足这个条件,该树就是搜索二叉树。

递归过程中还要去获取当前树的最大值和最小值,就用当前根节点与其左右子树的最大值和最小值分别比较即可,这样就能得到结果。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public static class Info {
        // 以当前节点为根节点的树的最大值
        public int max;
        // 以当前节点为根节点的树的最小值
        public int min;
        // 以当前节点为根节点的树是不是搜索二叉树
        public boolean isSearch;

        public Info(int max, int min, boolean isSearch) {
            this.max = max;
            this.min = min;
            this.isSearch = isSearch;
        }
    }

    // 方法一:二叉树递归套路
    public boolean isValidBST(TreeNode root) {
        Info info = process(root);
        return info == null ? true : info.isSearch;
    }

    /**
     判断一个树是不是搜索二叉树有两种方法:
     1、判断该树的中序遍历是不是升序,搜索二叉树的中序遍历是升序的。
     2、通过递归来判断

     该方法就是递归判断搜索二叉树

     递归的思路就是保证左右子树都是搜索二叉树,并且当前节点比其左子树的最大值大,比其右子树的最小值小,只要满足这个条件,该树就是搜索二叉树
     递归过程中还要去获取当前树的最大值和最小值,就用当前根节点与其左右子树的最大值和最小值分别比较即可,这样就能得到结果
     */
    public Info process(TreeNode root) {
        // 递归出口,当递归到为空的叶子节点时,递归结束,开始向上返回
        if (root == null) {
            return null;
        }

        // 递归调用。将左右子树进行递归,来判断他们是否为二叉搜索树
        Info infoLeft = process(root.left);
        Info infoRight = process(root.right);

        // 准备返回给上一层的结果数据
        // 以该层root节点为根节点的树是否为搜索二叉树
        boolean isSearch = false;
        // 以该层root节点为根节点的树最大值节点为多少(包括根节点)
        int max = root.val;
        // 以该层root节点为根节点的树最小值节点为多少(包括根节点)
        int min = root.val;

        // 下面需要获取以该层root节点为根节点的树的最大值和最小值
        // 这里需要判断两次,分别将当前节点的val与左右子树的最大值和最小值进行比较,才能得到最后的结果

        // 与左子树比较
        if (infoLeft != null) {
            // 当前节点的值与其左子树最大值进行比较,获得最大值
            max = Math.max(max, infoLeft.max);
            // 当前节点的值与其左子树最小值进行比较,获得最小值
            min = Math.min(min, infoLeft.min);
        }

        // 与右子树比较
        if (infoRight != null) {
            max = Math.max(max, infoRight.max);
            min = Math.min(min, infoRight.min);
        }

        // 下面需要根据左右子树的情况来判断以当前节点为根节点的树是不是搜索二叉树。
        // 如果左右节点都不为空,说明存在左右子树
        if (infoLeft != null && infoRight != null) {
            // 当左右子树都是搜索二叉树,并且左子树的最大值小于当前节点的值,右子树的最小值大于当前结点的值,说明以该节点为根节点的树是搜索二叉树
            isSearch = infoLeft.isSearch && infoRight.isSearch && root.val > infoLeft.max && root.val < infoRight.min;
            // 如果只存在左子树
        } else if (infoLeft != null) {
            // 仅判断左子树即可
            isSearch = infoLeft.isSearch && root.val > infoLeft.max;
            // 如果只存在右子树
        } else if (infoRight != null) {
            // 进判断右子树即可
            isSearch = infoRight.isSearch && root.val < infoRight.min;
            // 如果无孩子节点
        } else {
            // 直接默认该树为搜索二叉树
            isSearch = true;
        }

        // 递归接口,将该层结果数据返回给上一层
        return new Info(max, min, isSearch);
    }
}

方法二:检查中序遍历是否为升序 

中序遍历一下,如果依次递增,就是BST,如果不依次递增就不是BST。

利用Morris遍历改写中序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
// 利用Morris遍历改中序遍历,来检查中序遍历是否为升序
public boolean isValidBST(TreeNode root) {
    if (root == null) {
        return true;
    }
    TreeNode cur = root;
    TreeNode mostRight = null;
    Integer pre = null;
    boolean ans = true;
    while (cur != null) {
        mostRight = cur.left;
        if (mostRight != null) {
            while (mostRight.right != null && mostRight.right != cur) {
                mostRight = mostRight.right;
            }
            if (mostRight.right == null) {
                mostRight.right = cur;
                cur = cur.left;
                continue;
            } else {
                mostRight.right = null;
            }
        }
        // 判断中序遍历是否为升序
        if (pre != null && pre >= cur.val) {
            // 不要return,完整跑完Morris遍历后再return,因为Morris会修改二叉树,需要让Morris遍历都执行完,把二叉树再还原回去
            ans = false;
        }
        // 遍历过程中要记录中序遍历的上一个节点
        pre = cur.val;
        cur = cur.right;
    }
    return ans;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/125459.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序框架02

目录 1.框架简介 2.视图层 View 2.2 WXML 2.3 WXSS 2.4 JS 3.事件 4.逻辑层 APP service 4.1 生命周期 4.2 页面路由 4.3模块化 1.框架简介 小程序开发框架的目标是通过尽可能简单、高效的方式让开发者可以在微信中开发具有原生 APP 体验的服务。 整个小程序框架系统分为两部…

山东大学机器学习课程资源索引

实验 完整实验代码获取 github repo 【ML实验4】多分类贝叶斯模型 【ML实验5】SVM&#xff08;手写数字识别、核方法&#xff09; 【ML实验6】K-means&#xff08;图像压缩&#xff09; 【ML实验7】人脸识别综合项目&#xff08;PCA、多分类SVM&#xff09; 一个PCA加速技巧 …

数据治理:企业数据治理蓝图

参考《一本书讲透数据治理》、《数据治理》等 文章目录企业数据治理体系企业数据治理9个要素企业数据治理4个层面企业数据治理之道企业数据治理之法企业数据治理之术企业数据治理之器企业数据治理体系 数据治理、数据管理、数据管控三者是什么关系&#xff1f;很多人都搞混&am…

【Spring(二)】IoC入门案例(XML版)

文章目录前言1.IoC入门案例总结前言 上篇文章我们讲了IOC和DI两个核心概念&#xff0c;本篇文章我们会在Spring的环境下来实现它们&#x1f4aa;&#x1f4aa;。 1.IoC入门案例 我们先来实现IoC也就是管理Bean的这套模式&#xff0c;我们先来说说这套程序应该怎么做&#xff0c…

深度学习Week12-训练自己的数据集(YOLOv5)

这周接着详细解析小白YOLOv5全流程-训练实现数字识别_牛大了2022的博客-CSDN博客_yolov5识别数字&#xff0c;上周入门教大家下载配置环境&#xff0c;如果没有的话请参考上周的文章深度学习Week11-调用官方权重进行检测&#xff08;YOLOv5&#xff09;_牛大了2022的博客-CSDN博…

《IDC MarketScape:2022全球通用计算机视觉厂商评估》出炉,腾讯云智能入选

近日&#xff0c;全球领先的IT市场研究和咨询公司IDC发布了2022年度《MarketScape&#xff1a;全球通用计算机视觉厂商评估》报告&#xff08;以下简称“报告”&#xff09;&#xff0c;腾讯云智能凭借在计算机视觉领域领先的技术积累、出色的产品能力和丰富的行业落地实践&…

案例分享:硬件敏捷

“没有人能够在硬件领域推动以两周为单位的循环迭代&#xff01;”当人们谈起敏捷方法在包含了硬件及软件产品开发时&#xff0c;第一反应都是类似的论调。然而&#xff0c;已经有一些团队&#xff0c;尝试将已有的可靠硬件开发理念与少量从敏捷软件中借鉴的新鲜思想结合&#…

系统日志- Journal and Rsyslog

Log文件 Rsyslog 的配置文件/etc/rsyslog.conf Rsyslog的旧的信息会在最前面&#xff0c;新的信息会在最下面。 tail -f /var/log/messages #可以动态监控日志信息logger 发送日志信息 logger -p user.notice #“内容” -p选项测试实验&#xff1a; 1.在/etc/rsyslog.d/文…

基于ThinkPHP框架开发的全套家政服务小程序源码(带调试视频)

家政服务小程序源码 在线派单 商家入驻 多城市带积分开源小程序 了解更多内容可私信我。 1、独立版 ThinkPHP框架 后端全开源&#xff1b; 2. 开发语言&#xff1a;PHP&#xff1b; 3. 数据库&#xff1a;MySQL&#xff1b; 4.小程序端&#xff1a;Uniapp&#xff1b; 5.…

Vuex基础概念用法(新手入门)

一.Vuex概念及解释 定义: vue全局状态管理器。有了Vuex在任意组件/页面都可以访问vuex数据&#xff0c;当数据更新的时候&#xff0c;引用vuex的组件视图会自动更新。也就是说Vuex实现数据全局共享&#xff0c;响应式更新。 1.state&#xff08;存放状态&#xff09; $store…

《flask》flask+mqtt联动快速上手

简介 本文旨在介绍如何快速上手联动flask mqtt&#xff0c;本文将会给出一个简单的demo&#xff0c;用于演示在如何通过访问flask接口来触发mqtt&#xff0c;并在flask运行的基础的上对mqtt进行订阅。 快速上手 因为有项目需求&#xff0c;所以需要flask mqtt进行联动&…

Docker网络中篇-docker网络的四种类型

通过上一篇学习,我们对docker网络有了初步的了解。本篇,咱们就来实战docker网络。 docker网络实战 实战docker网络,我们将从以下几个案例来讲解 1:birdge是什么? 2:host 3:none 4:container 实战网络类型如下: 在docker中,网络的配置是以json格式存在的,下面…

知识变现创业者必读——《知识变现实操手册》

现在越来越多人&#xff0c;正在跑步进入知识变现创业这个赛道。 为什么进入这个赛道&#xff0c;因为能赚钱钱啊&#xff0c;大部分人是受到了知识变现大咖们日入万元&#xff0c;月入十万&#xff0c;这些赚钱效益的刺激&#xff0c;匆忙进入的。 我问一句&#xff0c;你知识…

网络路由技术和协议

网络路由是网络通信的重要组成部分。路由可帮助您的网络组件从可用选项中选择最佳网络路径。这使得网络通信高效可靠。启用此功能的硬件组件称为路由器。监控和管理路由器是网络管理员日常工作中不可或缺的一部分。由于路由器可以决定网络连接和可用性的成败&#xff0c;因此了…

MATLAB-plot绘图函数

plot函数是MATLAB中最核心的二维绘图函数&#xff0c;它有多种语法格式可以实现多种功能。 plot函数的基本调用格式如下。 plot(y) 当y为向量时&#xff0c;是以y的分量为纵坐标、元素序号为横坐标&#xff0c;用直线依次连接数据点&#xff0c; 绘制曲线。若y为实矩阵&#…

【技术分享】如何实现功能完备性能优异的RTMP、RTSP播放器?

技术背景 这几年&#xff0c;我们对接了太多有RTSP或RTMP直播播放器诉求的开发者&#xff0c;他们当中除了寻求完整的解决方案的&#xff0c;还有些是技术探讨&#xff0c;希望能借鉴我们播放端的开发思路或功能特性&#xff0c;完善自己的产品。 忙里偷闲&#xff0c;今天我…

【GO】K8s 管理系统项目[API部分--Pv]

K8s 管理系统项目[API部分–Pv] 1. 接口实现 service/dataselector.go type pvCell corev1.PersistentVolumefunc(p pvCell) GetCreation() time.Time {return p.CreationTimestamp.Time }func(p pvCell) GetName() string {return p.Name }2. Pv功能 service/pv.go 2.1 获…

沙龙预告|2023 年展望 Web3 Crypto

全长 621 字&#xff0c;预计阅读 3 分钟 作者&#xff1a;MiX 起起落落的2022年即将结束&#xff0c;随着传统金融机构的采用和 Web3 创新的不断深入&#xff0c;加密领域已经成为全球资本和技术创新的重要组成部分。 总结2022&#xff0c;展望2023&#xff0c;这对每一位加…

【数据库与缓存保持一致性】

文章目录1. 方案1先更新数据库&#xff0c;再更新缓存先更新缓存&#xff0c;在更新数据库2. 方案2先更新数据库&#xff0c;在删缓存先删缓存&#xff0c;在更新数据库3. 方案3—如何保证两个操作都能执行成功&#xff1f;重试机制订阅 MySQL binlog1. 方案1 先更新数据库&am…

S7-1200PLC与组态王进行TCP通信的基本方法和步骤

S7-1200PLC与组态王进行TCP通信的基本方法和步骤 如下图所示,打开博途软件,新建一个项目,设置该PLC的IP地址为:192.168.1.102, 如下图所示,在OB1中编写一段简单的启保停程序, 如下图所示,打开Kingview组态王软件,点击文件—新建工程, 新建一个项目,如下图所示…