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

文章目录

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

题目

标题和出处

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

出处:236. 二叉树的最近公共祖先

难度

5 级

题目描述

要求

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

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

示例

示例 1:

示例 1

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

示例 2:

示例 2

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

示例 3:

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

数据范围

  • 树中结点数目在范围 [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 的公共祖先,其中深度最大的公共祖先即为最近公共祖先。

考虑示例 1 和示例 2 使用的二叉树。

图 1

示例 1 中, p = 5 p = 5 p=5 q = 1 q = 1 q=1。结点 5 5 5 对应的路径是 [ 3 , 5 ] [3, 5] [3,5],结点 1 1 1 对应的路径是 [ 3 , 1 ] [3, 1] [3,1],唯一的公共祖先是 3 3 3,最近公共祖先是 3 3 3

示例 2 中, p = 5 p = 5 p=5 q = 4 q = 4 q=4。结点 5 5 5 对应的路径是 [ 3 , 5 ] [3, 5] [3,5],结点 4 4 4 对应的路径是 [ 3 , 5 , 2 , 4 ] [3, 5, 2, 4] [3,5,2,4],公共祖先是 3 3 3 5 5 5,最近公共祖先是 5 5 5

当遍历到一个结点时,即可得到从根结点到该结点的路径,将路径反转之后即可得到从该结点到根结点的路径。对于结点 p p p q q q 分别得到从当前结点到根结点的路径,两条路径相交处的结点即为最近公共祖先。

为了得到反向路径,需要使用哈希表存储每个结点的父结点。对二叉树深度优先搜索,在遍历过程中将每个结点的父结点存入哈希表。遍历结束之后,从结点 p p p 出发,每次移动到当前结点的父结点,直到到达根结点时,即得到从结点 p p p 到根结点的路径。在寻找从结点 p p p 到根结点的路径的过程中,使用哈希集合存储访问过的结点。然后从结点 q q q 出发,每次移动到当前结点的父结点,寻找从结点 q q q 到根结点的路径,第一个遇到的在哈希集合中的结点即为最近公共祖先。

代码

class Solution {Map<TreeNode, TreeNode> parentMap = new HashMap<TreeNode, TreeNode>();Set<TreeNode> visited = new HashSet<TreeNode>();public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {dfs(root);TreeNode node = p;while (node != null) {visited.add(node);node = parentMap.get(node);}TreeNode ancestor = q;while (!visited.contains(ancestor)) {ancestor = parentMap.get(ancestor);}return ancestor;}public void dfs(TreeNode node) {TreeNode left = node.left, right = node.right;if (left != null) {parentMap.put(left, node);dfs(left);}if (right != null) {parentMap.put(right, node);dfs(right);}}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。深度优先搜索访问每个结点一次,需要 O ( n ) O(n) O(n) 的时间,对于结点 p p p 和结点 q q q,寻找从当前结点到根结点的路径的时间不超过 O ( n ) O(n) O(n),因此总时间复杂度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是哈希表、哈希集合和栈的空间,哈希表需要 O ( n ) O(n) O(n) 的空间存储每个结点的父结点,哈希集合和栈的空间取决于二叉树的高度,二叉树的高度不超过 O ( n ) O(n) O(n),因此总空间复杂度是 O ( n ) O(n) O(n)

解法二

思路和算法

考虑二叉树中的每个结点,可能有以下情况。

  1. 如果 p p p q q q 中的一个结点是当前结点,另一个结点在以当前结点为根结点的子树中,则当前结点即为 p p p q q q 的最近公共祖先。

  2. 如果 p p p q q q 分别位于当前结点的左子树和右子树中,则当前结点即为 p p p q q q 的最近公共祖先。

  3. 如果 p p p q q q 位于当前结点的同一个子树中,则 p p p q q q 的最近公共祖先位于当前结点的同一个子树中。

上述情况中的情况 1 和情况 2 为当前结点是 p p p q q q 的最近公共祖先,对于情况 3,需要在子树中继续寻找 p p p q q q 的最近公共祖先,最近公共祖先一定满足情况 1 或情况 2。因此,最近公共祖先可能的情况一共有两种。

为了寻找最近公共祖先,需要从根结点开始深度优先搜索。对于每个结点,在当前子树中寻找 p p p q q q 是否存在,如果 p p p q q q 都存在则返回最近公共祖先,如果 p p p q q q 只存在一个则返回存在的结点。以下将 p p p q q q 统称为「目标结点」。

具体做法如下。

  1. 如果当前结点为 p p p q q q,则返回当前结点。

  2. 否则,在当前结点的左子树和右子树中分别寻找 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) {if (root == p || root == q) {return root;}TreeNode leftAncestor = null, rightAncestor = null;if (root.left != null) {leftAncestor = lowestCommonAncestor(root.left, p, q);}if (root.right != null) {rightAncestor = lowestCommonAncestor(root.right, p, q);}if (leftAncestor != null && rightAncestor != null) {return root;}return leftAncestor != null ? leftAncestor : rightAncestor;}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点都被访问一次。

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

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

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

相关文章

Redis 的集群模式实现高可用

来源&#xff1a;Redis高可用&#xff1a;武林秘籍存在集群里&#xff0c;那稳了~ (qq.com) 1. 引言 前面我们已经聊过 Redis 的主从同步&#xff08;复制&#xff09;和哨兵机制&#xff0c;这期我们来聊 Redis 的集群模式。 但是在超大规模的互联网应用中&#xff0c;业务规…

2023年Java核心技术大会(Core Java Week 2023)-核心PPT资料下载

一、峰会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家&#xff1b;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里&#xff0c;Java阵营的确受到了前所未有的挑战&#xff0c;出现了更多更…

机器视觉系统选型-定光照强度

同一个外形结构的光源&#xff0c;光照强度受如下影响&#xff1a; 单颗灯珠的亮度灯珠排列的数量和密度漫射板/防护板的材质&#xff08;透明、半透明、全漫射&#xff09; 在合理范围内提升光照强度&#xff0c;可降低对相机曝光时长的要求 外形结构尺寸相同的两款光源&am…

Mac电脑VSCode配置PHP开发环境

1.安装 PHP 首先&#xff0c;打开终端&#xff0c;安装 Homebrew&#xff0c;输入如下命令&#xff1a; $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 安装了 Homebrew 之后&#xff0c;你可以使用下面的…

基于C++实现循环赛日程表(分治算法)

一、问题描叙 设有n2^k个运动员&#xff0c;要进行网球循环赛。现在要设计一个满足以下要求的比赛日程表 每个选手必须与其他n-1个选手各赛一场每个选手一天只能赛一次循环赛一共进行n-1天 二、问题分析 按此要求可将比赛日程表设计成n行n-1列的表&#xff0c;在表中第 i 行…

uniapp中使用render.js进行openers、arcgis等地图操作

uniapp中使用render.js进行openers、arcgis等地图操作 一、为啥需要render.js render.js主要作用于APP上&#xff0c;因为Uniapp本质为vuejshtml进行开发&#xff0c;整个技术栈还是H5&#xff0c;对DOM元素进行操作。而APP中没用Dom元素这个概念。因此利用render.js这个视图层…

NX二次开发UF_CAM_ask_cam_preferences 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;里海NX二次开发3000例专栏 UF_CAM_ask_cam_preferences Defined in: uf_cam.h int UF_CAM_ask_cam_preferences(UF_CAM_preferences_p_t prefs ) overview 概述 This function provides the current settings of the CAM pre…

【Linux】安全审计-audit

文章目录 一、audit简介二、开启auditd服务三、相关文件四、审计规则五、审计日志查询及分析附录1&#xff1a;auditctl -h附录2&#xff1a;systemcall 类型 参考文章&#xff1a; 1、安全-linux audit审计使用入门 2、audit详细使用配置 3、Linux-有哪些常见的System Call&a…

优步让一切人工智能化

优步(Uber)的商业模式建立在对数据的颠覆性使用上--通过将双方智能手机的位置数据关联起来&#xff0c;将出租车司机与乘客配对。这意味着&#xff0c;它可以比传统出租车公司更快地安排司机去接乘客&#xff0c;极大地冲击了传统出租车公司的业务。 优步自成立以来&#xff0…

【Linux】-进程间通信-命名管道文件(没有关系的进程间进行通信),以及写一个日志模板

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

Vue3.0和2.0语法不同分析

前言&#xff1a;本篇文章只做VUE3.0和VUE2.0语法上的不同分析&#xff0c;不做性能和源码架构等的分析。 一、VUE3.0和VUE2.0代码结构不同 VUE3.0代码实例 <template><div><span>count is {{ count }}</span><span>plusOne is {{ plusOne }}…

Games104现代游戏引擎笔记 面向数据编程与任务系统

Basics of Parallel Programming 并行编程的基础 核达到了上限&#xff0c;无法越做越快&#xff0c;只能通过更多的核来解决问题 Process 进程 有独立的存储单元&#xff0c;系统去管理&#xff0c;需要通过特殊机制去交换信息 Thread 线程 在进程之内&#xff0c;共享了内存…

Linux本地docker一键部署traefik+内网穿透工具实现远程访问Web UI管理界面

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

LabVIEW和NIUSRP硬件加快了认知无线电开发

LabVIEW和NIUSRP硬件加快了认知无线电开发 对于电视频谱&#xff0c;主用户传输有两种类型&#xff1a;广播电视和节目制作和特殊事件(PMSE)设备。广播塔的位置已知&#xff0c;且覆盖电视传输塔&#xff08;复用器&#xff09;附近的某个特定地理区域&#xff08;称为排除区域…

进程管理(四)

管程概念及实现要旨 管程引入了条件变量condition。 wait操作,把当前进程挂到条件变量对应的阻塞队列上去,signal把条件队列上的对手进程唤醒。 注意:条件变量的signal操作和信号量的signal是有区别的。条件变量的signal可能啥都不干,如果有阻塞的进程唤醒,没有啥事都不做…

从零开始的C++(十八)

avl树中insert的模拟实现 avl树特点&#xff1a; 1.是搜索二叉树 2.每个结点的左右子树高度差的绝对值不超过2 inser模拟实现&#xff1a; // 右单旋void RotateR(Node* pParent){Node* parent pParent;Node* pr parent->_pRight;Node* prl pr->_pLeft;//记录父节点…

红海营销时代,内容占位的出海品牌更有机会营销占位

#01 品牌出海&#xff1a;内容占位就是品牌营销占位 红海营销时代&#xff0c;内容信息充斥着用户周边。无论线上还是线下&#xff0c;生活工作、休闲娱乐等不同场景内&#xff0c;广告信息均无孔不入。对于用户来说&#xff0c;能记住的品牌或者商品往往寥寥无几。 占位营销…

全网好评!12个网络工程师必备工具!

你们好&#xff0c;我的网工朋友。 今天来一期久违的工具推荐。工欲善其事必先利其器&#xff0c;好的工具势必会让网工们如虎添翼。 快速掌握正确的工具&#xff0c;意味着你可以轻松地完成复杂的工作。 但市面上的软件太多了&#xff0c;到底选用哪个工具&#xff0c;这还…

【最新Tomcat】IntelliJ IDEA通用配置Tomcat教程(超详细)

前言 IntelliJ IDEA是一个强大的集成开发环境&#xff0c;能够大大简化Java应用程序的开发和部署过程。而Tomcat作为一个流行的Java Web服务器&#xff0c;其与IntelliJ IDEA的整合能够提供便捷的开发环境&#xff0c;让开发人员更专注于代码的创作与优化。 在配置IntelliJ IDE…

linux在非联网、无网络环境下,使用yumdownload、reportrack方法安装rpm包

文章目录 前言1、下载yum-utils​​2、yumdownloader3、repotrack4、安装5、yumdownloader和repotrack的区别总结 前言 当开发者在联网环境下使用Linux时&#xff0c;可以轻松地通过yum或apt-get安装软件。然而&#xff0c;在公司和企业中&#xff0c;由于安全原因&#xff0c…