二叉树:二叉树的最近公共祖先

news2024/12/23 13:52:42

二叉树的最近公共祖先

文章目录

    • 一、题目描述
    • 二、解题思路
    • 三、代码解析

一、题目描述

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

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。

请添加图片描述

以上面这个图为例子:

5和1 的最近公共祖先就是3。

二、解题思路

刚看到这个题,肯定会有点懵,我开始也很懵,根本不知道从何下手,没关系,只需要先将这个思路理解了,先将这个方法掌握啦,掌握的方法多了,慢慢就有了自己的思路了。

用什么遍历序列?

这题要问的是给定p,q的最近公共祖先。很明显,是找指定孩子结点的祖先结点。
那么,我们是不是应该先检查子孙,通过检查子孙返回的结果来判断当前结点是否是目标结点。

比如上面的例子,最后返回的是3,这个3是我们在检查完5和1后,发现5和1满足条件才认定3是最终结果的。

那么请问大家,用哪个遍历顺序?

A:中左右
B:左中右
C:左右中

答案明显是:C
根据遍历左右子树的结果来判断当前结点是不是要求的结点。

怎么用后序遍历解决这个问题?

首先考虑,我们对于每一个结点的左右子树应该返回什么内容,才能让判断这个结点是否是最近公共祖先?

还是刚才的例子,
我们发现3->left是5满足给定的p=5
我们发现3->right是1满足给定的q=1
所以,我们认为3是5,1的公共祖先。

那如果要求p = 6, q = 1的最近公共祖先呢?

请添加图片描述

明显能看出来,6和1的最近公共祖先还是3。
那是怎么判断的呢?

递归遍历3的左子树,如果左子树出现目标p或者q,就p或者q一层层返回上来。
遍历5的时候,如果5的左子树或者右子树出现p或者q,就返回上来。

总之:

无论在这个树的哪个位置找到了p或者q都要能把p,q返回到上一层,方便上层结点做判断。
所以说,递归函数返回值,返回的就是这个子树中是否有p,或者q。
如果有p或者q,就返回p或者q,如果没有就返回NULL

怎么通过左右子树返回的值判断最终的结果呢?

左右子树返会值会出现那些情况,有那些值是我们要返回的?
首先,如果遇到p,q肯定要返回。
其次,如果找到了【最近公共祖先】肯定也要返回
再次,如果不是上面两种情况,返回NULL就行了。

三、代码解析

看了上面的解析,可能还有点懵,那下面再结合具体代码理解

template<class T>
TreeNode<T>* lowestCommonAncestor(TreeNode<T>* root, TreeNode<T>* p, TreeNode<T>* q) {
//思路
/*
    题目给了两个二叉树结点的指针,要返回这两个指针的最近的公共祖先。
    首先,这个题只能使用后序遍历,左右中。因为后序是先访问两个叶子,再访问中间结点。
    那根据后序遍历的访问顺序怎么操作呢?
    我们将后序每个结点后序左右子树遍历的结果保存在left和right中。
    如果有p那left保存的就是p
    (只要左子树出现p就,整个左子树返回的就是p,q同理,右子树同理,如果p,q都没有出现,就返回NULL)

    这样,对每一个结点都可以得到这个结点左右子树返回来的值。
    我们就根据这个结点左右子树返回来的值来判断这个结点是不是p,q的最近公共结点。
    怎么判断呢?左右子树可能跟返回如下三个值:p, q, NULL
    那么请问,一个结点的左右子树满足那种情况的时候,这个结点是p, q的最近公共祖先呢?
    当然只有两种情况:left:q, right:p 和left:p, right:q这两种情况了。
    所以,这时候只需要做判断,如果左右子树返回的都不是NULL那么,当前处理的这个结点就是p,q的最近公共祖先了。
    结束。
*/
    //1.返回值和参数:返回值仍然是Treenode
    //2.递归终止的条件
    /*什么时候递归终止?
     2.1 当前访问的结点是p或者q
     2.2 当前访问到了空节点NULL(这个树是空树,或者叶子结点的孩子)
    */
    if (root == q || root == p || root == NULL) return root;//对叶子结点的处理
    //3.单层递归处理逻辑
    //3.1 后序遍历左子树
    TreeNode<T>* left = lowestCommonAncestor(root->left, p, q);
    //3.2 后序遍历右子树
    TreeNode<T>* right = lowestCommonAncestor(root->right, p, q);
    //3.3 后序遍历处理中间结点

    //问题:这里为什么判断的是左右子树返回值不为NULL,为什么不判断左右子树返回值是p,q?
    /*
        因为,我们要向上传递的是四种值:NULL,p,q,最近公共祖先
        如果,判断是左右子树返回的是否是p,q那么,如果左右子树有一个子树出现了【最近公共祖先】
        那这个结果会因为不是p,q而传递不上去。
        反之,我们之和NULL做比较,只要不是NULL的都往上传,那无论在哪里找到了【最近公共祖先】
        都会被递归返回上去。
    */
    //得到了这个结点左右子树的值,就要判断这个结点是不是p,q的最近公共结点了
    if (left != NULL && right != NULL) return root;//左右子树都不为空,说明左右子树返回的是p,q或者q,p具体顺序我们不关心

    if (left != NULL && right == NULL) return left;//一个不为空,返回不为空的那个
    else if (left == NULL && right != NULL) return right;//同理
    else {
        return NULL;//只剩下最后一种情况,左右两边都返回的是NULL
    }

}

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

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

相关文章

Vue实现下载文件而非浏览器直接打开

问题背景 对于一个txt文本、图片、视频、音频等浏览器可以直接使用浏览器进行预览的文件&#xff0c; 使用传统的a标签加download属性进行下载是行不通的&#xff0c;会在浏览器直接打开&#xff0c;因此需要搞一个新的方式进行下载。 实现流程 实现思路 这里使用Vue自定义…

ElasticSearch从入门到出门【中】

文章目录DSL查询文档DSL查询分类全文检索查询使用场景基本语法示例精准查询term查询range查询地理坐标查询矩形范围查询附近查询复合查询相关性算分算分函数查询布尔查询搜索结果处理排序普通字段排序地理坐标排序分页基本的分页深度分页问题高亮高亮原理实现高亮RestClient查询…

档案数据智能采集工厂模型设计与实现

档案信息化从业人员肯定对异构系统数据采集过程中碰到的各种问题深有体会&#xff0c;有源系统供应商不配合的&#xff1b;数据接口不开放的&#xff1b;归档数据不符合规范的&#xff1b;数据敏感不提供的&#xff1b;等等&#xff1b;不一而足。但不幸的是档案信息系统处于政…

C 语言零基础入门教程(二十二)

C 错误处理 C 语言不提供对错误处理的直接支持&#xff0c;但是作为一种系统编程语言&#xff0c;它以返回值的形式允许您访问底层数据。在发生错误时&#xff0c;大多数的 C 或 UNIX 函数调用返回 1 或 NULL&#xff0c;同时会设置一个错误代码 errno&#xff0c;该错误代码是…

VS2017编译c dll的方法-编译bsio

VS2017编译c dll 有三种方法 &#xff08;1&#xff09;.h和.c文件函数增加 __declspec(dllexport) &#xff08;2&#xff09;仅在.h函数添加__declspec(dllexport) &#xff08;3&#xff09;使用.def文件&#xff0c;不用在.h和.c文件的函数前增加__declspec(dllexport) …

【数据结构初阶】顺序表的实现(文末附原码)

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;数据结构初阶 ⭐代码仓库&#xff1a;Data Structure 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff…

基于C讲解协程设计原理

协程设计原理 背景 以epoll处理fd为例&#xff1a; func () {while (1) {epoll_wait();for(;;) {recv();send();}} }在IO操作较为密集的情况下&#xff08;网络IO和磁盘IO操作多&#xff0c;CPU计算少&#xff09;&#xff0c;由于检测到IO事件后&#xff0c;需要进行同步的…

美颜sdk动态贴纸是什么?

美颜sdk如今已经成了广大视频拍摄平台的刚需&#xff0c;用户们也习惯了这种新颖的拍摄形式&#xff0c;原相机被无情“打入冷宫”&#xff0c;特别是短视频和直播平台中&#xff0c;绝大部分用户都在使用美颜sdk的趣味功能进行拍摄&#xff0c;“动态贴纸”就是一个非常好的例…

什么是PEPPOL BIS?

和常见的X12以及EDIFACT类似&#xff0c;PEPPOL BIS也是一种EDI标准&#xff0c;主要用于B2G和B2B交易&#xff0c;在欧盟的应用十分广泛。在业务场景中&#xff0c;PEPPOL不单单只是用于发票&#xff0c;从下单到开票流程中均可提供标准化的数据传输。 在此前的文章中&#x…

[Ansible系列]ansible tag介绍

简介 在大型项目当中&#xff0c;通常一个playbook会有非常多的task。而我们每次执行这个playbook时&#xff0c;都会将 所有task运行一遍。而事实上&#xff0c;在实际使用过程中&#xff0c;我们可能只是想要执行其中的一部分任务而已&#xff0c; 并不想把整个playbook完整跑…

【单链表】数据结构单链表的实现

前言&#xff1a;在之前的学习中我们已经了解了顺序表的相关知识内容&#xff0c;但是顺序表我们通过思考可以想到如下问题&#xff1a; 中间/头部的插入删除&#xff0c;时间复杂度为O(N)增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。增容…

性能技术分享|Jmeter+InfluxDB+Grafana搭建性能平台

一、引言最近在公司做性能技术分享时&#xff0c;发现同事对环境搭建能力&#xff0c;还是有些欠缺。或许&#xff0c;这也是大部分性能测试工程师所欠缺的技能。因为绝大部分的性能测试工程师&#xff0c;要么是使用测试开发架构师搭建的性能平台&#xff0c;要么自己使用Jmet…

【Unity3D】激光灯、碰撞特效

1 需求描述 本文将模拟激光灯&#xff08;或碰撞&#xff09;特效&#xff0c;详细需求如下&#xff1a; 从鼠标位置发射屏幕射线&#xff0c;检测是否与物体发生碰撞当与物体发生碰撞时&#xff0c;在物体表面覆盖一层激光灯&#xff08;或碰撞&#xff09;特效本文代码见→激…

振弦采集模块VMTool 配置工具的传感器数据读取

振弦采集模块VMTool 配置工具的传感器数据读取 连接传感器 将振弦传感器两根线圈引线分别连接到 VM 模块模块的 SEN和 SEN-两个管脚。 通常不分正负极&#xff0c;任意连接即可。 连接模块电源 使用 5V~12V 直流电源连接到 VM 模块的 VIN 和 GND&#xff0c;电源正极连接到 VIN…

【数据结构基础】树 - 平衡二叉树(AVL)

平衡二叉树&#xff08;Balanced Binary Tree&#xff09;具有以下性质&#xff1a;它是一棵空树或它的左右两个子树的高度差的绝对值不超过1&#xff0c;并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等。 最小二叉平…

数学建模与数据分析 || 1. 数学建模简介

数学建模简介 文章目录数学建模简介1. 数学建模比赛的理解2. 一般数据分析的流程3. 机器学习与统计数据分析4. 各种编程软件仅仅是工具&#xff0c;对问题的观察视角和解决问题的策略才是关键2.1 数学建模的特点2.2 以 python&#xff08;jupyter notebook工作界面&#xff09;…

JSR303校验(表单参数校验)

1、maven坐标<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>3.0.1</version> </dependency>2、校验规则3、定义好校验规则还需要开启校验&#…

用户区网络缓冲区

用户区网络缓冲区 为什么要有用户层缓冲区 TCP内核协议栈&#xff0c;每个连接都有一个接收缓冲区和一个发送缓冲区&#xff0c;为啥用户层也要有&#xff1a; 为啥要有接收缓冲区 生产者速度大于消费者速度&#xff1a;客户端发送地太快&#xff0c;服务器处理不过来&#…

SpringWebflux 执行流程和核心 API

SpringWebflux 基于 Reactor&#xff0c;默认使用容器是 Netty&#xff0c;Netty 是高性能的 NIO 框架&#xff0c;异步非阻 塞的框架 Netty_百度百科 (baidu.com)BIO、NIO、AIO_y_凉介的博客-CSDN博客_bin nio &#xff08;1&#xff09;Netty BIO 每一个请求过来会占用一个…

【系列05】类与对象 面向对象 封装继承多态 类 内部类

面向对象&#x1f601; 文章为本人随课程记录笔记形成 跟随老师"秦疆&#xff08;遇见狂神说)" 非常欢迎大家在文章下面留言评论互相交流,也欢迎大家有问题可以联系本人或者本人公众号 &#x1f609;学思则安 参考课程https://www.kuangstudy.com/course?cid1 有问…