力扣日记12.21【二叉树篇】98. 验证二叉搜索树

news2024/12/26 2:57:46

力扣日记:【二叉树篇】98. 验证二叉搜索树

日期:2023.12.21
参考:代码随想录、力扣

98. 验证二叉搜索树

题目描述

难度:中等

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

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

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

示例 1:
在这里插入图片描述

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

示例 2:
在这里插入图片描述

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

提示:

  • 树中节点数目范围在[1, 10^4] 内
  • -2^31 <= Node.val <= 2^31 - 1

题解

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
#define SOLUTION 2
public:
#if SOLUTION == 0
    // 下面代码有问题,搞不定了。。。
    /*
    bool isValidBST(TreeNode* root) {
        if (root == nullptr)    return false;
        // 需要先对根节点进行处理
        if (root->left != nullptr && root->left->val >= root->val)  return false;
        if (root->right != nullptr && root->right->val <= root->val)    return false;
        // 根节点暂且满足条件,递归判断其子树  
        return traversal(root->left, root->val, true) && traversal(root->right, root->val, false);
    }
    // 参数为当前子树的根节点,以及该子树的父节点的值,以及该子树是左子树还是右子树,返回值为该子树是否为二叉搜索树
    bool traversal(TreeNode* root, int midNodeVal, bool leftTree) {
        if (root == nullptr)    return true;
        // 左为空,则左不为false
        // 左不为空, 
        if (root->left != nullptr) {
            // 首先判断左子节点
            if (root->left->val >= root->val)   return false;
            if (!leftTree) {
                // 如果是右子树,还要保证其左节点比该子树的父节点大
                if (root->left->val <= midNodeVal)  return false;
            }
        }  
        if (root->right != nullptr) {
            // 首先判断右子节点
            if (root->right->val <= root->val)  return false;
            if (leftTree) {
                // 如果是左子树,要保证其右节点比该子树的父节点小
                if (root->right->val >= midNodeVal) return false;
            }
        }
        // 遍历左右节点
        bool left = traversal(root->left, root->val, true);
        if (left == false)  return false;
        bool right = traversal(root->right, root->val, false);
        return right;
    }
    */
#elif SOLUTION == 1
    // 思路:利用二叉搜索树的特性!!!
    // 二叉搜索树中序遍历是有序的!!!
    // 方式1:先转换为数组,再判断数组是否有序
    bool isValidBST(TreeNode* root) {
        // 先中序遍历得到数组
        vector<int> result;
        traversal(root, result);
        // 对数组进行判断
        // 如果数组为空或只有1个,则为true(空的树也为二叉搜索树!)
        if (result.size() <= 1) return true;
        // size >= 2
        // 遍历数组
        for (int i = 1; i < result.size(); i++) {
            // 如果后面的元素 <= 前面的元素(注意也不能相等),则不是二叉搜索树
            if (result[i] <= result[i-1])   return false;
        }
        return true;
    }
    // 中序遍历:左中右
    void traversal(TreeNode* root, vector<int>& result) {
        if (root == nullptr)   return;
        // 左
        traversal(root->left, result);
        // 中
        result.push_back(root->val);
        // 右
        traversal(root->right, result);
    }
#elif SOLUTION == 2
    // 方式2:直接在进行中序遍历的同时判断是否有序
    TreeNode* pre = nullptr;    // 保存上一个节点(用来比较)
    bool isValidBST(TreeNode* root) {
        // 空,直接返回true
        if (root == nullptr)    return true;
        // 左
        bool left = isValidBST(root->left);
        if (left == false)  return false;
        // 中
        // 如果pre不为空,当前节点值需要比上一个节点值大
        if (pre != nullptr && root->val <= pre->val)    return false;   // false 则不需要继续迭代了也不需要更新pre了
        // 如果没有违反,更新pre,并继续递归
        pre = root;
        // 右
        bool right = isValidBST(root->right);
        return right;
    }
#endif
};

复杂度

时间复杂度:
空间复杂度:

思路总结

  • 本题就像是脑筋急转弯,得从二叉搜索树转到这样一个思路:
  • 如果一棵树是二叉搜索树,其中序遍历一定是有序的!!!(从小到大)
  • 因此,本题有两种方式来验证:
    • 方式1:先用中序遍历(左中右)得到遍历数组;再对数组判断是否有序(较简单)
    • 方式2:直接在中序遍历的同时判断是否有序(需要在递归中保存上一个值,稍复杂)

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

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

相关文章

24_28-Golang函数详解

**Golang **函数详解 主讲教师&#xff1a;&#xff08;大地&#xff09; 合作网站&#xff1a;www.itying.com** **&#xff08;IT 营&#xff09; 我的专栏&#xff1a;https://www.itying.com/category-79-b0.html 1、函数定义 :::info 函数是组织好的、可重复使用的、用…

云渲染如何使用?其实很简单,只需3步就搞定了!

很多人第一次接触云渲染&#xff0c;对云渲染不了解&#xff0c;不知道云渲染怎么用&#xff0c;其实很简单&#xff0c;只需要3步就搞定了。 第一步&#xff1a;下载并安装客户端 到炫云官网下载客户端&#xff0c;下载完直接点击安装就可以&#xff0c;炫云的效果图渲染和动…

【代码规范】统一参数校验、结果返回

统一参数校验&#xff1a; 在编写Controller层的代码时&#xff0c;时常会有这种情况出现&#xff1a; RestController RequestMapping("/user") public class UserController {Resourceprivate UserService userService;PostMapping("register")public S…

【基础知识】大数据组件YARN简述

YARN是一个分布式的资源管理系统。 YARN是Hadoop系统的核心组件&#xff0c;主要功能包括负责在Hadoop集群中的资源管理&#xff0c;负责对作业进行调度运行以及监控。 ResourceManager 负责集群的资源管理与调度&#xff0c;为运行在YARN上的各种类型作业分配资源。 非HA集…

设计模式03结构型模式

结构型模式 参考网课:黑马程序员Java设计模式详解 博客笔记 https://zgtsky.top/ 结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式&#xff0c;前者采用继承机制来组织接口和类&#xff0c;后者釆用组合或聚合来组合对象。 由于…

通过讯飞 API 接口用 Vue 实现实时语音转写

通过讯飞 API 接口用 Vue 实现实时语音转写 项目地址 前言 本项目中实时语音能够转写的最大时间为 60 s&#xff0c; 这个数据也是由 API 提供方给限制掉的 为什么我会需要这个点击按钮以后能够实现实时语音的转写呢&#xff0c;因为被课程所迫&#xff0c;选了这个方向就必…

linux 性能优化-内存优化

CPU 管理一样&#xff0c;内存管理也是操作系统最核心的功能之一。内存主要用来存储系统和应 用程序的指令、数据、缓存等。 1.内存原理 1.1.内存映射 1.1.1.日常生活常说的内存是什么? 我的笔记本电脑内存就是 8GB 的这个内存其实是物理内存物理内存也称为主存&#xff0…

Java最全面试题专题---5、Spring面试题(1)

Spring概述&#xff08;10&#xff09; 什么是spring? Spring是一个轻量级Java开发框架&#xff0c;最早有Rod Johnson创建&#xff0c;目的是为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题。它是一个分层的JavaSE/JavaEE full-stack&#xff08;一站式&#xff…

联合体(C语言)

小伙伴们又来学习知识啦~&#xff0c;今天我要给大家介绍一下联合体的使用&#xff0c;话不多说&#xff0c;我们开始今天的正题吧&#xff01; 联合体的介绍 C语言的联合体&#xff08;union&#xff09;是一种特殊的数据类型&#xff0c;它可以在同一内存空间中存储不同的数…

龙迅LT86102UXE HDMI一分二HDMI,支持音频剥离,支持4K60HZ

描述&#xff1a; 龙迅 LT86102UXE HDMI2.0 分路器具有符合 HDMI2.0/1.4 规范的 1&#xff1a;2 分路器、最大 6Gbps 高速数据速率、自适应均衡 RX 输入和预加重 TX 输出&#xff08;用于支持长电缆应用&#xff09;、内部 TX 通道交换以实现灵活的 PCB 布线。 LT86102UXE HDM…

机器学习之线性回归(Linear Regression)附代码

概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…

Ubuntu 常用命令之 passwd 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 在Ubuntu系统中&#xff0c;passwd命令用于更改用户的密码。系统管理员可以使用此命令更改任何用户的密码&#xff0c;而普通用户只能更改自己的密码。 passwd命令的参数如下 -l, --lock&#xff1a;锁定密码&#xff0c;使账户…

Apache+PHP环境配置 手动配置

准备工作&#xff0c;在G盘新建一个WAMP目录 1.获取Apache 打开下载地址Apache VS17 binaries and modules download&#xff0c;下载 httpd-2.4.58-win64-VS17.zip 将下载好的httpd-2.4.58-win64-VS17.zip拷贝到G:\WAMP目录下并解压到当前目录&#xff0c;得到Apache24目录 …

石墨匣钵,预计到2025年将达到3.973亿美元

石墨匣钵是陶瓷和耐火材料工业用于烧制和烧结各种材料的高温容器。在陶瓷产品需求增加和耐火材料行业增长的推动下&#xff0c;全球石墨匣钵市场在过去几年出现了显着增长。2020 年全球石墨匣钵市场价值为 3.039 亿美元&#xff0c;预计到 2025 年将达到 3.973 亿美元&#xff…

找不到x3daudio1_7.dll文件的解决方法分享

今天我想和大家分享的是关于“找不到X3DAudio1_7.dll无法继续执行代码问题”的解决方法&#xff0c;以及X3DAudio1_7.dll丢失是什么意思&#xff0c;它的作用是什么&#xff0c;以及丢失对计算机有什么影响。 首先&#xff0c;我们来解释一下X3DAudio1_7.dll是什么。X3DAudio1…

Python Hook钩子函数详解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python编程中&#xff0c;Hook钩子函数是一种重要的编程机制&#xff0c;允许程序在运行时的特定点执行自定义代码&#xff0c;以修改或扩展程序的行为。本文将深入介绍Python中Hook钩子函数的基本概念、使用场…

Axure RP 8 for Mac/win中文版:打造完美交互式原型设计体验

Axure RP 8&#xff0c;一款引领潮流的交互式原型设计工具&#xff0c;为设计师提供了无限的可能性&#xff0c;让他们能够创造出逼真的原型&#xff0c;从而更好地展示和测试他们的设计。 Axure RP 8拥有丰富的功能和工具&#xff0c;让设计师可以轻松地创建出复杂的交互式原…

程序员的50大JVM面试问题及答案

文章目录 1.JDK、JRE、JVM关系&#xff1f;2.启动程序如何查看加载了哪些类&#xff0c;以及加载顺序&#xff1f;3. class字节码文件10个主要组成部分?4.画一下jvm内存结构图&#xff1f;5.程序计数器6.Java虚拟机栈7.本地方法栈8.Java堆9.方法区10.运行时常量池&#xff1f;…

DDPM推导笔记

各位佬看文章之前&#xff0c;可以先去看看这个视频&#xff0c;并给这位up主点赞投币&#xff0c;这位佬讲解的太好了&#xff1a;大白话AI 1.前置知识的学习 1.1 正态分布特性 ​ &#xff08;1&#xff09;正态分布的概率密度函数 f ( x ) 1 2 π σ e − ( x − μ ) …

day38 1220

作业1&#xff1a;select客户端 1 #include <myhead.h>2 #define SERPORT 88883 #define SERIP "192.168.125.159"4 5 #define CLIPORT 66666 #define CLIIP "192.168.125.159"7 8 int main(int argc, const char *argv[])9 {10 int ret -1;11 …