[模版总结] - 树的基本算法4 -最近公共祖先 LCA

什么是最近公共祖先LCA

LCA:在一个树中,距离两个节点p,q最近可以是其本身并且同时包含这两个子节点的节点

题目连接

Leetcode 236 - LCA
Leetcode 1644 - LCA II
Leetcode 1650 - LCAIII
Leetcode 1123 - LCA of Deepest leaves

基本思路

Leetcode 236 - LCA
Leetcode 1644 - LCA II
求解LCA的基本思路就是分治法,两个节点的相对位置关系有三种情况:

  1. p和q在同一侧某个子树中,比如下图 p在H点,q在B点。
  2. p和q在两侧不同子树中,比如下图p在D点,q在C点
  3. 边界情况,p,q中有一个节点不存在在该树中

基于上述三种情况,分治递归过程中如果当前节点是p 或者 q那么返回该节点如果当前节点不是p, q查看左右子树递归返回结果

  1. 如果左右有一个是p或者q或者一个非空节点(说明找到了p, q的LCA)那么返回那个点
  2. 如果左右既有p又有q那么返回当前节点说明当前点就是LCA, 如果左右都是空指针那么返回空指针说明p, q和LCA都没有找到。
    解决第三种情况可以建立一个count, 遇到p和q都count++最后返回LCA时保证count==2再返回即可

二叉树示意图

代码如下
class Solution {
public:int count = 0;TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {auto res = dc(root, p, q);return count==2? res: nullptr;}TreeNode* dc(TreeNode* root, TreeNode* p, TreeNode* q) {if (!root) return nullptr;auto l = dc(root->left, p, q);auto r = dc(root->right, p, q);if (root==p || root==q) {count++;return root; } else if ((l==q && r==p) || (l==p && r==q)) return root;else return !l? r: l;}};

时间复杂度: O ( N ) \mathcal{O}(N) O(N) N代表树节点总数
空间复杂度: O ( H ) \mathcal{O}(H) O(H) H代表树的深度,也就是栈的深度

Leetcode 1650

题目描述也是求解两个节点LCA但是树的结构中提供了parent这个节点,树有保存父节点。这道题思路就和 Leetcode 160 找到两个相交链表的相交点。p和q保证是同一个树的两个节点。

基本思路就是让p和q一直通过parent向上层移动,如果p到了root就把p指向q继续移动,如果q到了root就把q指向p继续移动,p和q最后一定会相交在相交点位置,返回这个点就是LCA

为什么一定会相交在相交点LCA位置?

  • 假设p到LCA的距离是 x, q到LCA的距离为y, LCA到root的距离为z
  • 根据上面的思路,p总共移动距离 x+z+y ; q总共移动距离 y+z+x 移动距离相等并在LCA处相交
代码如下
class Solution {
public:Node* lowestCommonAncestor(Node* p, Node * q) {/*[1,2,3,null,4]12  34    和找两个链表的第一个相交点类似// 第一种左右两边p -> 1 -> 2 ->3 ->4 ->5->6q ->7a + c + b b + c + a// 第二种没到终点前找到另一个就返回另一个p -> 2-> qp = 2, q = 4p = 1, q = 2a + b b + a      */auto pp = p;auto qq = q;while (p && q) {if (q==p) return q;q = q->parent;p = p->parent;// 如果p或者q就是LCA,那么移动p,q时后面的点一定会走到前面的点,直接返回这个点即可if (q==pp || p==qq) return q==pp? pp: qq;//到root了,回到另一个点pp或着qq继续走直到相遇if (!q) q=pp; if (!p) p=qq;}return nullptr;}
};

时间复杂度:通常 O ( X + Y + Z ) \mathcal{O}(X+Y+Z) O(X+Y+Z) x指p到LCA经过节点数,y指q到LCA经过节点数, z指LCA到root经过节点数
空间复杂度: O ( 1 ) \mathcal{O}(1) O(1)

Leetcode 1123

题目描述给一个二叉树找到他的所有最深的叶子节点LCA。和之前题目不同的是,这道题最深的叶子节点可能有不止两个,而且你还需要找到最深的叶子节点。
求解LCA的基本思路还是一样,不同的地方在于要在返回节点给上一层递归时,返回深度信息进行打擂台

  1. 如果左右子树返回结果都不为空,判断结果深度是否相等?相等那就返回当前节点LCA, 如果不同就返回深度更深的那个结果
  2. 如果左右子树返回结果一个为空一个不为空,那就返回不为空的结果即可
代码如下
class Solution {
public:int h = 0;TreeNode* lcaDeepestLeaves(TreeNode* root) {// dfs找到所有的deepest leaf 然后第二次给这个list的节点找LCA,由于auto res = dc(root, 0);return res.first;}pair<TreeNode*, int> dc(TreeNode* root, int h) {if (!root) return {root, -1};if (!root->left && !root->right) return {root, h};auto l = dc(root->left, h+1);auto r = dc(root->right, h+1);// 如果两边返回的leaf同深度,返回当前节点和该深度// 如果两边返回的leaf不同深度,返回深的那个if (l.second==-1 || r.second==-1) return l.second==-1? r: l;else if (l.second==r.second) return {root, l.second};else return l.second>r.second? l: r;}
};

时间复杂度: O ( N ) \mathcal{O}(N) O(N) N为节点个数
空间复杂度: O ( H ) \mathcal{O}(H) O(H) H为递归深度

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

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

相关文章

永磁同步电机末端振动抑制(输入整形)

文章目录 1、前言2、双惯量系统3、输入整形3.1 ZV整形器3.2 ZVD整形器3.3 EI整形器 4、伺服系统位置环控制模型5、仿真5.1 快速性分析5.2 鲁棒性分析 参考 1、前言 什么是振动抑制&#xff1f;对于一个需要精确定位的系统&#xff0c;比如机械臂、塔吊、码头集装箱等&#xff…

jQuery-Word-Export 使用记录及完整修正文件下载 jquery.wordexport.js

参考资料&#xff1a; jQuery-Word-Export导出word_jquery.wordexport.js下载-CSDN博客 近期又需要自己做个 Html2Doc 的解决方案&#xff0c;因为客户又不想要 Html2pdf 的下载了&#xff0c;当初还给我费尽心思解决Html转pdf时中文输出的问题&#xff08;html转pdf文件下载之…

【Redis_Day6】Hash类型

【Redis_Day6】Hash类型 Hash类型操作hash的命令hset&#xff1a;设置hash中指定的字段&#xff08;field&#xff09;的值&#xff08;value&#xff09;hsetnx&#xff1a;想hash中添加字段并设置值hget&#xff1a;获取hash中指定字段的值hexists&#xff1a;判断hash中是否…

【CSP CCF记录】201809-2第14次认证 买菜

题目 样例输入 4 1 3 5 6 9 13 14 15 2 4 5 7 10 11 13 14 样例输出 3 思路 易错点&#xff1a;仅考虑所给样例&#xff0c;会误以为H和W两人的装车时间是一一对应的&#xff0c;那么提交结果的运行错误就会让你瞬间清醒。 本题关键是认识到H和W的装车时间不一定一一对应&…

Unity清除所有的PlayerPrefs

方法1&#xff1a; 直接在你的代码中加入这句 PlayerPrefs.DeleteAll(); 方法2&#xff1a; 点击编辑窗口的这里

非交换几何与黎曼ζ函数:数学中的一场革命性对话

非交换几何与黎曼ζ函数&#xff1a;数学中的一场革命性对话 非交换几何&#xff08;Noncommutative Geometry, NCG&#xff09;是数学的一个分支领域&#xff0c;它将经典的几何概念扩展到非交换代数的框架中。非交换代数是一种结合代数&#xff0c;其中乘积不是交换性的&…

微信小程序下拉刷新与上拉触底的全面教程

微信小程序下拉刷新与上拉触底的全面教程 引言 在微信小程序的开发中,用户体验至关重要。下拉刷新和上拉触底是提高用户交互体验的重要功能,能够让用户轻松获取最新数据和内容。本文将详细介绍这两个功能的实现方式,结合实际案例、代码示例和图片展示,帮助开发者轻松掌握…

数据库的联合查询

数据库的联合查询 简介为什么要使⽤联合查询多表联合查询时MYSQL内部是如何进⾏计算的构造练习案例数据案例&#xff1a;⼀个完整的联合查询的过程 内连接语法⽰例 外连接语法 ⽰例⾃连接应⽤场景示例表连接练习 ⼦查询语法单⾏⼦查询多⾏⼦查询多列⼦查询在from⼦句中使⽤⼦查…

论文阅读:A fast, scalable and versatile tool for analysis of single-cell omics data

Zhang, K., Zemke, N.R., Armand, E.J. et al. A fast, scalable and versatile tool for analysis of single-cell omics data. Nat Methods 21, 217–227 (2024). 论文地址&#xff1a;https://doi.org/10.1038/s41592-023-02139-9 代码地址&#xff1a;https://github.com…

Hive离线数仓结构分析

Hive离线数仓结构 首先&#xff0c;在数据源部分&#xff0c;包括源业务库、用户日志、爬虫数据和系统日志&#xff0c;这些都是数据的源头。这些数据通过Sqoop、DataX或 Flume 工具进行提取和导入操作。这些工具负责将不同来源的数据传输到基于 Hive 的离线数据仓库中。 在离线…

设计模式之 模板方法模式

模板方法模式是行为型设计模式的一种。它定义了一个算法的骨架&#xff0c;并将某些步骤的实现延迟到子类中。模板方法模式允许子类在不改变算法结构的情况下重新定义算法的某些特定步骤。 模板方法模式的核心在于&#xff1a; 封装算法的骨架&#xff1a;通过父类中的模板方…

【分治】--- 快速选择算法

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; 算法Journey &#x1f3e0; 颜色划分 &#x1f4cc; 题目解析 颜色分类 本题要求我们原地对元数组划分0,1,2三个区域,也就是不能使用辅助数组&#xf…

万物皆可Docker,在NAS上一键部署最新苹果MacOS 15系统

万物皆可Docker&#xff0c;在NAS上一键部署最新苹果MacOS 15系统 哈喽小伙伴们还&#xff0c;我是Stark-C~ 最近苹果Mac mini 2024款在政府补贴的加持下&#xff0c;仅需3500块钱左右就能到手确实挺香的。我看很多评论区的小伙伴跃跃欲试&#xff0c;但是也有不少之前从未体…

C++设计模式行为模式———状态模式

文章目录 一、引言二、状态模式三、总结三、总结 一、引言 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。其实现可完成类似有限状态机的功能。换句话说&#xff0c;一个对象可以处…

vscode自动打印日志插件

自动日志工具&#xff08;Auto Logger Log&#xff09; 概述 自动日志工具&#xff08;Auto Logger Log&#xff09; 是一款 VS Code 扩展&#xff0c;用于简化生成调试日志的过程。它可以为选中的变量自动生成打印语句&#xff0c;帮助开发者快速记录和调试代码。该扩展支持多…

优雅的不等式——Hard

上一文《Easy》末尾出现了又要我们证明的例子&#xff0c;Hard难度就是继续答题答下去 其实一样可以用那篇文章https://zhuanlan.zhihu.com/p/669285539中的式子继续算下去&#xff0c;但是有三个系数&#xff0c;实在是太费时间和人力了 翻到下面的第十九种类型&#xff0c;可…

虚拟局域网PPTP配置与验证(二)

虚拟局域网PPTP配置与验证(二) windows VPN客户端linux 客户端openwrt客户端性能验证虚拟局域网PPTP配置与验证(一)虚拟局域网PPTP配置与验证(二) : 本文介绍几种客户端连接PPTP服务端的方法,同时对linux/windows/openwrt 操作系统及x86、arm硬件平台下PPTP包转发性能进…

Move 合约部署踩坑笔记:如何解决 Sui 客户端发布错误Committing lock file

Move 共学活动&#xff1a;快速上手 Move 开发 为了帮助更多开发者快速了解和掌握 Move 编程语言&#xff0c;Move 共学活动由 HOH 社区、HackQuest、OpenBuild、KeyMap 联合发起。该活动旨在为新手小白提供一个良好的学习平台&#xff0c;带领大家一步步熟悉 Move 语言&#…

介绍一下strupr(arr);(c基础)

hi , I am 36 适合对象c语言初学者 strupr(arr)&#xff1b;函数是把arr数组变为大写字母 格式 #include<string.h> strupr(arr); 返回值为arr 链接分享一下arr的意义(c基础)(必看)(牢记)-CSDN博客 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #incl…

进程间通信5:信号

引入 我们之前学习了信号量&#xff0c;信号量和信号可不是一个东西&#xff0c;不能混淆。 信号是什么以及一些基础概念 信号是一种让进程给其他进程发送异步消息的方式 信号是随时产生的&#xff0c;无法预测信号可以临时保存下来&#xff0c;之后再处理信号是异步发送的…