面试经典算法系列之二叉树17 -- 验证二叉树

面试经典算法32 - 验证二叉树

LeetCode.98
公众号:阿Q技术站

问题描述

给你一个二叉树的根节点 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

思路

为了判断一个二叉树是否是有效的二叉搜索树,可以利用二叉搜索树的性质:对于每个节点,其左子树的所有节点都小于当前节点,右子树的所有节点都大于当前节点。同时,左右子树也必须分别是有效的二叉搜索树。

递归
  1. 定义一个辅助函数 isValidBSTHelper,用于递归判断以当前节点为根的子树是否是有效的二叉搜索树。
  2. 在辅助函数中,传入当前节点、允许的最小值和最大值。
  3. 如果当前节点为空,说明是有效的二叉搜索树,返回 true。
  4. 如果当前节点的值不在最小值和最大值的范围内,说明不是有效的二叉搜索树,返回 false。
  5. 递归判断左子树和右子树,左子树的最大值为当前节点的值,右子树的最小值为当前节点的值。
  6. 如果左子树和右子树都是有效的二叉搜索树,则当前节点也是有效的二叉搜索树,返回 true。
非递归
  1. 使用栈来模拟中序遍历的过程,从根节点开始,先将左子节点依次入栈,直到最左下的叶子节点。
  2. 弹出栈顶节点,判断其值是否大于前一个节点的值(如果存在)。如果不满足递增关系,则不是有效的二叉搜索树,返回 false。
  3. 将当前节点的右子节点入栈,继续遍历右子树。
  4. 重复步骤 2 和步骤 3,直到栈为空且所有节点都遍历完毕。

图解

  1. 创建空栈 s 和当前节点指针 curr,初始化 prevlong 类型最小值

  1. 如果当前节点不为空或栈不为空,则将当前节点入栈,然后将当前节点指向其左子节点,重复此步骤直到当前节点为空。

  1. 如果当前节点为空,说明已经到达最左下角的节点,将栈顶节点弹出。

  1. 栈顶元素的值不小于long类型的最小值。将 prev 更新为当前节点值。

  1. 处理右子节点。

此时,当前节点值小于前一个节点的值,说明不是二叉搜索树,返回 false。

参考代码

C++
递归
#include <iostream>
#include <limits>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        return isValidBSTHelper(root, numeric_limits<long>::min(), numeric_limits<long>::max());
    }

private:
    bool isValidBSTHelper(TreeNode* root, long minVal, long maxVal) {
        if (!root) {
            return true; // 空节点是有效的二叉搜索树
        }

        if (root->val <= minVal || root->val >= maxVal) {
            return false; // 当前节点的值不在允许的范围内,不是有效的二叉搜索树
        }

        // 递归判断左子树和右子树
        return isValidBSTHelper(root->left, minVal, root->val) && isValidBSTHelper(root->right, root->val, maxVal);
    }
};

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

int main() {
    vector<int> nodes = {2, 1, 3}; // 二叉搜索树的中序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    Solution solution;
    bool result = solution.isValidBST(root); // 判断二叉树是否是有效的二叉搜索树
    cout << (result ? "true" : "false") << endl; // 输出结果

    return 0;
}
非递归
#include <iostream>
#include <stack>
#include <limits>

using namespace std;

// 二叉树节点的定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    bool isValidBST(TreeNode* root) {
        stack<TreeNode*> s; // 辅助栈,用于模拟中序遍历过程
        TreeNode* curr = root; // 当前节点
        long prev = numeric_limits<long>::min(); // 用于保存前一个节点的值,初始化为 long 类型最小值

        while (curr || !s.empty()) {
            while (curr) {
                s.push(curr); // 将当前节点入栈
                curr = curr->left; // 遍历左子树
            }
            curr = s.top(); // 获取栈顶节点
            s.pop(); // 弹出栈顶节点

            if (curr->val <= prev) {
                return false; // 如果当前节点值小于等于前一个节点的值,说明不是二叉搜索树,返回 false
            }

            prev = curr->val; // 更新前一个节点的值为当前节点的值
            curr = curr->right; // 处理右子节点
        }

        return true; // 遍历完所有节点,返回 true
    }
};

// 创建二叉树
TreeNode* createTree(vector<int>& nodes, int index) {
    if (index >= nodes.size() || nodes[index] == -1) {
        return nullptr; // 如果节点为空,则返回nullptr
    }
    TreeNode* root = new TreeNode(nodes[index]); // 创建当前节点
    root->left = createTree(nodes, 2 * index + 1); // 创建左子树
    root->right = createTree(nodes, 2 * index + 2); // 创建右子树
    return root; // 返回当前节点
}

int main() {
    vector<int> nodes = {2, 1, 3}; // 二叉搜索树的中序遍历序列
    TreeNode* root = createTree(nodes, 0); // 创建二叉树
    Solution solution;
    bool result = solution.isValidBST(root); // 判断二叉树是否是有效的二叉搜索树
    cout << (result ? "true" : "false") << endl; // 输出结果

    return 0;
}
Java
import java.util.Stack;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

class Solution {
    public boolean isValidBST(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>(); // 辅助栈,用于模拟中序遍历过程
        TreeNode curr = root; // 当前节点
        long prev = Long.MIN_VALUE; // 用于保存前一个节点的值,初始化为 long 类型最小值

        while (curr != null || !stack.isEmpty()) {
            while (curr != null) {
                stack.push(curr); // 将当前节点入栈
                curr = curr.left; // 遍历左子树
            }
            curr = stack.pop(); // 获取栈顶节点

            if (curr.val <= prev) {
                return false; // 如果当前节点值小于等于前一个节点的值,说明不是二叉搜索树,返回 false
            }

            prev = curr.val; // 更新前一个节点的值为当前节点的值
            curr = curr.right; // 处理右子节点
        }

        return true; // 遍历完所有节点,返回 true
    }
}

public class Main {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(2);
        root.left = new TreeNode(1);
        root.right = new TreeNode(3);

        Solution solution = new Solution();
        boolean result = solution.isValidBST(root); // 判断二叉树是否是有效的二叉搜索树
        System.out.println(result); // 输出结果
    }
}
Python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Solution:
    def isValidBST(self, root: TreeNode) -> bool:
        stack = []  # 辅助栈,用于模拟中序遍历过程
        curr = root  # 当前节点
        prev = float("-inf")  # 用于保存前一个节点的值,初始化为负无穷

        while curr or stack:
            while curr:
                stack.append(curr)  # 将当前节点入栈
                curr = curr.left  # 遍历左子树
            curr = stack.pop()  # 获取栈顶节点

            if curr.val <= prev:
                return False  # 如果当前节点值小于等于前一个节点的值,说明不是二叉搜索树,返回 False

            prev = curr.val  # 更新前一个节点的值为当前节点的值
            curr = curr.right  # 处理右子节点

        return True  # 遍历完所有节点,返回 True

# 创建二叉树
root = TreeNode(2)
root.left = TreeNode(1)
root.right = TreeNode(3)

solution = Solution()
result = solution.isValidBST(root)  # 判断二叉树是否是有效的二叉搜索树
print(result)  # 输出结果

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频教程下载:用ChatGPT快速提升股票投资能力

学完此视频后可以获得&#xff1a; 学习如何使用人工智能/Chatgpt进行基础/快速/高级财务与研究分析 学习如何使用人工智能/Chatgpt对任何公司进行定性投资研究 学习如何使用人工智能/Chatgpt对任何公司进行定量投资研究 学习如何使用人工智能/Chatgpt创建、预测和分析财务…

考研日常记录

由于实在太无聊了 &#xff0c; 所以记录以下考研备考日常 &#xff0c; 增加一点成就感 &#xff0c; 获得一点前进动力。 2024.4.18 周四 课程情况&#xff1a; 无课 时间规划&#xff1a; 上午&#xff1a;休息 下午&#xff1a; 事项耗时进度备注写作业1h复习英语单词…

低噪声放大器是如何实现低噪声放大的功能的

灵敏度作为接收机最重要的指标之一,直接决定了接收机能分辨的最小信号。接收机的灵敏度计算公式如下所示。 Psensitivity=-174dBm+NF+10*lg(BW)+SNR 由接收机灵敏度的计算公式可知,影响接收机灵敏度的指标有噪声系数、带宽和信噪比,因此一旦带宽和信噪比确定了,那么能决…

隧道网络对讲广播音频终端-智慧工地网络报警求助箱

隧道网络对讲广播音频终端-智慧工地网络报警求助箱 SV-6007 网络对讲求助终端 一、描述 SV-6007是我司的一款壁挂式双按键求助对讲终端&#xff0c;具有10/100M以太网接口&#xff0c;其接收网络的音频数据&#xff0c;实时解码播放&#xff0c;还配置了麦克风输入和扬声器输…

[Qt网络编程]之UDP通讯的简单编程实现

hello&#xff01;欢迎大家来到我的Qt学习系列之网络编程之UDP通讯的简单编程实现。希望这篇文章能对你有所帮助&#xff01;&#xff01;&#xff01; 本篇文章的相关知识请看我的上篇文章: http://t.csdnimg.cn/UKyeM 目录 UDP通讯 基于主窗口的实现 基于线程的实现 UDP通讯…

【opencv】dnn示例-segmentation.cpp 通过深度学习模型对图像进行实时语义分割

模型下载地址&#xff1a; http://dl.caffe.berkeleyvision.org/ 配置文件下载&#xff1a; https://github.com/opencv/opencv_extra/tree/4.x/testdata/dnn 该段代码是一个利用深度学习进行语义分割的OpenCV应用实例。下面将详细解释代码的功能和方法。 引入库 引入了一些必要…

统一SQL-支持cast函数

统一SQL介绍 https://www.light-pg.com/docs/LTSQL/current/index.html 源和目标 源数据库&#xff1a;Oracle 目标数据库&#xff1a;Postgresql&#xff0c;TDSQL-MySQL&#xff0c;达梦8&#xff0c;LightDB-Oracle 操作目标 在Oracle中&#xff0c;cast函数允许将一种…

代码随想录-链表 | 142环形链表

代码随想录-链表 | 142环形链表 LeetCode 142-环形链表解题思路代码复杂度难点总结 LeetCode 142-环形链表 题目链接 题目描述 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#x…

死磕GMSSL通信-C/C++系列(一)

死磕GMSSL通信-C/C++系列(一) 最近再做国密通信的项目开发,以为国密也就简单的集成一个库就可以完事了,没想到能有这么多坑。遂写下文章,避免重复踩坑。以下国密通信的坑有以下场景 1、使用GMSSL guanzhi/GmSSL进行通信 2、使用加密套件SM2-WITH-SMS4-SM3 使用心得 ​…

Java学习-详述main方法、可变参数、数组的工具类、二维数组

详述main方法 【1】main方法&#xff1a;程序的入口&#xff0c;在同一个类中&#xff0c;如果有多个方法&#xff0c;那么虚拟机就会识别main方法&#xff0c;从这个方法作为程序的入口 【2】main方法格式严格要求&#xff1a; public static void main(String[] args){} p…

【NOI-题解】1320. 时钟旋转1323. 扩建花圃问题1462. 小明的游泳时间1565. 成绩(score)1345. 玫瑰花圃

文章目录 一、前言二、问题问题&#xff1a;1320. 时钟旋转问题&#xff1a;1323. 扩建花圃问题问题&#xff1a;1462. 小明的游泳时间问题&#xff1a;1565. 成绩&#xff08;score&#xff09;问题&#xff1a;1345. 玫瑰花圃 三、感谢 一、前言 本章节主要对基本运算中整数…

Windows系统搭建Plex网站结合内网穿透实现公网访问本地影音文件

文章目录 1.前言2. Plex网站搭建2.1 Plex下载和安装2.2 Plex网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 用手机或者平板电脑看视频&#xff0c;已经算是生活中稀松平常的场景了&#xff0c;特别是各…

奶酪——并查集,BFS,DFS(NOIP2017提高组)

目录 题目 思路 并查集 代码&#xff08;java&#xff09; BFS&#xff08;DFS同理&#xff09; 代码&#xff08;C&#xff09; 题目 思路 这个题目意思是有很多个球分布在一个三维空间内&#xff0c;如果这些球相切或者相交都可以互相到达&#xff0c;我们需要判断能否…

二、e2studio VS STM32CubeIDE之功能对比

目录 一、概述/目的 二、官网资料 2.1 stm32cubeide 2.2 e2studio 三、功能对比 二、e2studio VS STM32CubeIDE之功能对比 一、概述/目的 通过对比学习&#xff0c;更快速的掌握两款IDE 二、官网资料 2.1 stm32cubeide https://www.stmcu.com.cn/ecosystem/Cube/STM32C…

41、二叉树-二叉树的层序遍历

思路&#xff1a; 层序遍历就是从左到右依次遍历。这个时候就可以使用队列的方式。例如先把头节点入队&#xff0c;然后遍历开始&#xff0c;首先计算队列长度&#xff0c;第一层&#xff0c;长度为了&#xff0c;遍历一次&#xff0c;依次出队&#xff0c;头结点出队&#xff…

Codeforces Round 924 (Div. 2) ---- F. Digital Patterns ---- 题解

F. Digital Patterns&#xff1a; 题目描述&#xff1a; 思路解析&#xff1a; 要求在一个方块中&#xff0c;任意相邻的方块中他的透明度系数不能相同&#xff0c;这样的方块称为趣味性方块&#xff0c;问这样的方块有多少种。 那么我们可以相当&#xff0c;假设 a1 a2, 那…

iOS ------ Block的总结

前面看了Block的基本知识&#xff0c;和一些源码。但对于block怎么用的还不了解&#xff0c;代码中出现block会看不懂&#xff0c;现在来具体看一下Block的用法并做个总结。 1.Block是什么 block对象是一个C语言结构体&#xff0c;可以并入C和OC的代码中&#xff0c;Block本质…

每日OJ题_多源BFS①_力扣542. 01 矩阵(多源BFS解决最短路原理)

目录 多源BFS解决最短路算法原理 力扣542. 01 矩阵 解析代码 多源BFS解决最短路算法原理 什么是单源最短路 / 多源最短路&#xff1f; 之前的BFS解决最短路都是解决的单源最短路。 画图来说&#xff0c;单源最短路问题即为&#xff1a; 而对于多源最短路问题: 如何解决此…

微信小程序之点击事件

微信小程序中常用的点击事件主要是 tap&#xff0c;但除此之外还有其他的触摸类事件&#xff0c;用于不同的交互场景。以下是一些常见的点击和触摸相关的事件及其区别&#xff1a; 1、tap——最基本的点击事件&#xff0c;适用于一般的轻触交互&#xff0c;类似于 HTML 中的 c…

Pixverse:开启文生视频与图生视频新纪元

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…