二叉搜索树题目:二叉搜索树的最近公共祖先

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:二叉搜索树的最近公共祖先

出处:235. 二叉搜索树的最近公共祖先

难度

3 级

题目描述

要求

给定一个二叉搜索树,找到该树中两个指定结点的最近公共祖先。

最近公共祖先的定义为:两个结点 p \texttt{p} p q \texttt{q} q 的最近公共祖先是满足 p \texttt{p} p q \texttt{q} q 都是其后代的最低的结点 T \texttt{T} T(一个结点也可以是它自己的祖先)。

示例

示例 1:

示例 1

输入: root   =   [6,2,8,0,4,7,9,null,null,3,5],   p   =   2,   q   =   8 \texttt{root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8} root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 \texttt{6} 6
解释:结点 2 \texttt{2} 2 和结点 8 \texttt{8} 8 的最近公共祖先是结点 6 \texttt{6} 6

示例 2:

示例 2

输入: root   =   [6,2,8,0,4,7,9,null,null,3,5],   p   =   2,   q   =   4 \texttt{root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4} root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2 \texttt{2} 2
解释:结点 2 \texttt{2} 2 和结点 4 \texttt{4} 4 的最近公共祖先是结点 2 \texttt{2} 2。因为根据定义最近公共祖先结点可以为结点本身。

示例 3:

输入: root   =   [2,1],   p   =   2,   q   =   1 \texttt{root = [2,1], p = 2, q = 1} root = [2,1], p = 2, q = 1
输出: 2 \texttt{2} 2

数据范围

  • 树中结点数目在范围 [2,   10 5 ] \texttt{[2, 10}^\texttt{5}\texttt{]} [2, 105]
  • -10 9 ≤ Node.val ≤ 10 9 \texttt{-10}^\texttt{9} \le \texttt{Node.val} \le \texttt{10}^\texttt{9} -109Node.val109
  • 所有 Node.val \texttt{Node.val} Node.val 各不相同
  • p ≠ q \texttt{p} \ne \texttt{q} p=q
  • p \texttt{p} p q \texttt{q} q 均存在于给定的二叉搜索树中

解法一

思路和算法

如果结点 p p p q q q 之间的关系是祖先和后代的关系,则其中的祖先即为最近公共祖先。如果结点 p p p q q q 之间的关系不是祖先和后代的关系,则结点 p p p q q q 分别在最近公共祖先的两个子树中。

对于二叉搜索树中的任意结点,其左子树中的结点值都小于当前结点值,其右子树中的结点值都大于当前结点值。首先比较根结点值和结点 p p p q q q 的结点值,缩小寻找最近公共祖先的范围。

  • 如果根结点值比结点 p p p q q q 的结点值都大,则结点 p p p q q q 都在根结点的左子树中,因此根结点的左子结点一定是结点 p p p q q q 的公共祖先,应该在根结点的左子树中寻找最近公共祖先。

  • 如果根结点值比结点 p p p q q q 的结点值都小,则结点 p p p q q q 都在根结点的右子树中,因此根结点的右子结点一定是结点 p p p q q q 的公共祖先,应该在根结点的右子树中寻找最近公共祖先。

  • 如果根结点值介于结点 p p p 和结点 q q q 的结点值之间(可以等于其中的一个结点值),则根结点的任何一个子结点都不可能是结点 p p p q q q 的公共祖先,因此根结点是结点 p p p q q q 的最近公共祖先。

上述过程是一个递归的过程。递归的终止条件是当前结点值介于结点 p p p 和结点 q q q 的结点值之间,此时当前结点是结点 p p p q q q 的最近公共祖先,返回当前结点。对于其余情况,定位到最近公共祖先所在的子树,对该子树调用递归。

由于结点 p p p q q q 都存在于给定的二叉搜索树中,因此最近公共祖先一定存在。

代码

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        int maxVal = Math.max(p.val, q.val);
        int minVal = Math.min(p.val, q.val);
        if (root.val <= maxVal && root.val >= minVal) {
            return root;
        }
        return root.val > maxVal ? lowestCommonAncestor(root.left, p, q) : lowestCommonAncestor(root.right, p, q);
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。时间复杂度取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

解法二

思路和算法

递归实现可以改成迭代实现。从根结点开始搜索,如果当前结点值结点值比结点 p p p q q q 的结点值都大或者都小,则执行如下操作,直到当前结点值介于结点 p p p 和结点 q q q 的结点值之间。

  • 如果当前结点值比结点 p p p q q q 的结点值都大,则结点 p p p q q q 都在当前结点的左子树中,因此将当前结点移动到左子结点。

  • 如果当前结点值比结点 p p p q q q 的结点值都小,则结点 p p p q q q 都在当前结点的右子树中,因此将当前结点移动到右子结点。

搜索结束时,当前结点为结点 p p p q q q 的最近公共祖先,返回当前结点。

由于结点 p p p q q q 都存在于给定的二叉搜索树中,因此最近公共祖先一定存在。

代码

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        int maxVal = Math.max(p.val, q.val);
        int minVal = Math.min(p.val, q.val);
        TreeNode node = root;
        while (node.val > maxVal || node.val < minVal) {
            if (node.val > maxVal) {
                node = node.left;
            } else {
                node = node.right;
            }
        }
        return node;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。时间复杂度取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

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

相关文章

openstack(T版)公有云--Dashboard服务

公有云上OpenStack Train最小化安装_openstack最小化部署-CSDN博客 我的opensatck(T)是参考上面链接去部署完成的&#xff0c;在部署完Dashboard服务后&#xff0c;将要用浏览器访问的时候出现了404 500 Internal Server Error 等各种各样的问题&#xff0c;以下是我排查问题…

【Linux驱动】块设备驱动(二)—— 块设备读写(使用请求队列)

块设备的操作函数并没有类似于字符驱动中的read 和write函数&#xff0c;要实现读写操作&#xff0c;只能在请求处理函数中实现。这就分为两种&#xff0c;是否要使用请求队列&#xff0c;请求队列的主要作用是管理和调度IO请求。在以下情况中&#xff0c;一般需要用到请求队队…

基于SSM的便民自行车管理系统的开发与实现(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的便民自行车管理系统的开发与实现&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0…

基于单片机的智能寻光小车设计

摘 要&#xff1a;随着物联网技术的飞速发展和逐渐成熟&#xff0c;以单片机为主的智能小车在巡查、仓储、探险及国防等领域得到广泛应用。本文设计了一种基于单片机的智能寻光小车&#xff0c;该小车以STC89C52RC 芯片为设计核心&#xff0c;结合光敏传感器和超声波传感器等多…

FCIS 2023:洞悉网络安全新态势,引领创新防护未来

随着网络技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为全球共同关注的焦点。在这样的背景下&#xff0c;FCIS 2023网络安全创新大会应运而生&#xff0c;旨在汇聚业界精英&#xff0c;共同探讨网络安全领域的最新动态、创新技术和解决方案。 本文将从大会的…

【Java 数据结构】反射

反射 1 定义2 用途(了解)3 反射基本信息4 反射相关的类&#xff08;重要&#xff09;4.1 Class类(反射机制的起源 )4.1.1 Class类中的相关方法(方法的使用方法在后边的示例当中) 4.2 反射示例4.2.1 获得Class对象的三种方式4.2.2 反射的使用 5、反射优点和缺点 1 定义 Java的反…

python统计分析——卡方检验

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 用于数值计算的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 用于绘图的库 from matplotlib import pyplot as plt import seaborn as sns sns.set() 2、数据准…

转融通业务是什么?好处和弊端是什么?

转融通业务是指证券金融公司借入证券、筹得资金后&#xff0c;再转借给证券公司&#xff0c;为证券公司开展融资融券业务提供资金和证券来源&#xff0c;包括转融券业务和转融资业务两部分。从证券金融公司角度看&#xff0c;向证券公司提供资金和证券供其开展融资融券业务&…

主动网络安全:成本效率和危机管理的战略方法

如何面对复杂网络攻击的进攻策略以及零信任模型的作用。攻击后反应性网络安全策略的基本步骤&#xff0c;透明度和准备工作。 讨论采用主动网络安全方法的好处&#xff0c;特别是在成本效率和危机管理方面&#xff0c;进攻性安全测试对合规性和零日响应的影响。 组织应该更多…

【证书管理】实验报告

证书管理实验 【实验环境】 ISES客户端 【实验步骤】 查看证书 查看证书详细信息 选择任意证书状态&#xff0c;在下方“证书列表”中出现符合要求的所有证书。在“证书列表”中点击要查看证书&#xff0c;在右侧“证书详细信息”栏出现被选证书信息。 上述操作如图1.2.…

JAVA原型模式详解

原型模式 1 原型模式介绍 定义: 原型模式(Prototype Design Pattern)用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 西游记中的孙悟空 拔毛变小猴,孙悟空这种根据自己的形状复制出多个身外化身的技巧,在面向对象软件设计领…

ROS笔记一:工作空间和功能包

目录 工作空间 如何创建工作空间&#xff1a; 编译工作空间 设置环境变量 功能包 创建功能包 CMakeLists.txt package.xml 工作空间 ROS的工作空间是用来存放工程文件代码的文件夹 ROS的开发依赖于工作空间&#xff0c;包括编写代码、编译等都是在工作空间下进行的 工作空…

SQLite database实现加密

注意&#xff1a;以下操作以VS2022为开发工具&#xff0c;以C#为开发语言。 数据加密原因 软件在使用的各个场景&#xff0c;很多都需要数据具有保密性&#xff0c;于是对于数据库就需要加密。特别是在某些特定领域或存储敏感数据尤其如此。 SQLite加密实现 SQLite加密有两种…

防范恶意勒索攻击!亚信安全发布《勒索家族和勒索事件监控报告》

本周态势快速感知 本周全球共监测到勒索事件81起&#xff0c;事件数量有所下降&#xff0c;比上月降低20%。 lockbit3.0仍然是影响最严重的勒索家族&#xff1b;akira和incransom也是两个活动频繁的恶意家族&#xff0c;需要注意防范。 本周alphv勒索组织窃取MBC法律专业公司…

【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费

作者推荐 【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II 本文涉及知识点 动态规划汇总 LeetCode1928. 规定时间内到达终点的最小花费 一个国家有 n 个城市&#xff0c;城市编号为 0 到 n - 1 &#xff0c;题目保证 所有城市 都由双向道路 连接在一起…

Java设计模式大全:23种常见的设计模式详解(一)

本系列文章简介&#xff1a; 设计模式是在软件开发过程中&#xff0c;经过实践和总结得到的一套解决特定问题的可复用的模板。它是一种在特定情境中经过验证的经验和技巧的集合&#xff0c;可以帮助开发人员设计出高效、可维护、可扩展和可复用的软件系统。设计模式提供了一种在…

VS编译器对scanf函数不安全报错的解决办法(详细步骤)

&#x1f4da;博客主页&#xff1a;爱敲代码的小杨. ✨专栏&#xff1a;《Java SE语法》 | 《数据结构与算法》 | 《C生万物》 ❤️感谢大家点赞&#x1f44d;&#x1f3fb;收藏⭐评论✍&#x1f3fb;&#xff0c;您的三连就是我持续更新的动力❤️ &#x1f64f;小杨水平有…

第5节、S曲线加减速转动【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍步进电机S曲线相关内容&#xff0c;总共分四个小节讨论步进电机S曲线相关内容 5-1、S曲线加减速简介   根据上节内容&#xff0c;步进电机每一段的速度可以任意设置&#xff0c;但是每一段的…

【教程】ESP32-CAM使用WiFi和MQTT

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 连接MQTT 1、先安装库 2、默认你已有MQTT服务器 3、编写代码(跳过WiFi连接部分) #include <PubSubClient.h>// MQTT server details const char* mqtt_server "xxxxx.cn"; const int mqtt_po…

Spring Boot整合MyBatis Plus实现基本CRUD与高级功能

文章目录 1. 引言2. 项目搭建与依赖配置2.1 添加MyBatis Plus依赖2.2 配置数据源与MyBatis Plus 3. 实现基本CRUD功能3.1 创建实体类3.2 创建Mapper接口3.3 实现Service层3.4 控制器实现 4. 高级功能实现4.1 自动填充功能4.2 乐观锁功能4.3 逻辑删除功能 5. 拓展&#xff1a;My…