力扣日记12.24-【二叉树篇】236. 二叉树的最近公共祖先

news2024/10/1 7:46:38

力扣日记:【二叉树篇】236. 二叉树的最近公共祖先

日期:2023.12.24
参考:代码随想录、力扣
ps:提前祝 平安夜快乐!

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

题目描述

难度:中等

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

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

示例 1:
在这里插入图片描述

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

示例 2:
在这里插入图片描述

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

示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

  • 树中节点数目在范围 [2, 10^5] 内。
  • -10^9 <= Node.val <= 10^9
  • 所有 Node.val 互不相同
  • p != q
  • p 和 q 均存在于给定的二叉树中

题解

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    // 本题要找两个子节点的最近公共祖先,是一个从底往上找的过程(先找到子节点才能找其祖先)
    // 而要从底往上查找->想到是回溯->想到二叉树遍历中的天然回溯,即后序遍历(左右中,根据左右节点的返回值处理中节点逻辑)
    // 且从底往上找,则先找到的公共祖先一定是最近公共祖先(深度最大)
    // 关于如何判断一个节点是节点q和节点p的公共祖先:
    // 第一种情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者反之,那么该节点就是节点p和q的最近公共祖先
    // 第二种情况:节点本身p(q),是自己的祖先(实际上在代码实现中也包含在第一种情况中)

    // 递归参数与返回值:参数为当前节点与指定节点;返回值表示是否在当前节点的树中找到指定节点(或者找到公共祖先)
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 递归终止条件
        // 如果root为空节点了,则没有,返回空
        // 如果 root == q,或者 root == p,说明找到 q p ,则将其返回
        if (root == q || root == p || root == NULL)   return root;    
        // 如果根节点不为空或还没找到,则递归处理
        // 左(看左子树能不能找到p或q)
        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        // 右(看右子树能不能找到p或q)
        TreeNode* right = lowestCommonAncestor(root->right, p, q);
        // 中(对左右返回值的处理逻辑)
        // 如果左右不为空,说明左子树返回一个,右子树返回一个,则当前root为公共祖先(情况1)
        if (left != NULL && right != NULL)  return root;
        // 如果左为空而右不为空,说明右找到了一个或者直接找到公共祖先,返回右(包含了情况2)
        if (left == NULL && right != NULL)  return right;
        // 反之亦然
        if (left != NULL && right == NULL)  return left;
        // 如果都为空,则返回空
        return NULL;
    }
};

复杂度

时间复杂度:
空间复杂度:

思路总结

  • 本题想了想没有思路www直接看的代码随想录的…

  • 首先明确祖先的概念:一个节点,是 以该节点为根节点的树上的所有节点的祖先;关于最近公共祖先的概念则为题目所述

  • 本题思路(实际上是代码注释):

    • 本题要找两个子节点的最近公共祖先,是一个从底往上找的过程(先找到子节点才能找其祖先)
    • 而要从底往上查找->想到是回溯->想到二叉树遍历中的天然回溯,即后序遍历(左右中,根据左右节点的返回值处理中节点逻辑)
    • 且从底往上找,则先找到的公共祖先一定是最近公共祖先(深度最大)
    • 关于如何判断一个节点是节点q和节点p的公共祖先:
      • 第一种情况:如果找到一个节点,发现左子树出现结点p,右子树出现节点q,或者反之,那么该节点就是节点p和q的最近公共祖先
        在这里插入图片描述
      • 第二种情况:节点本身p(q),是自己的祖先(实际上在代码实现中也包含在第一种情况中)
        在这里插入图片描述
    • 递归的三部曲:
      • 递归参数与返回值:参数为当前节点与指定节点;返回值表示是否在当前节点的树中找到指定节点(或者找到公共祖先)
      • 递归终止条件:
        • 如果root为空节点了,则没有,返回空
        • 如果 root == q,或者 root == p,说明找到 q p ,则将其返回
      • 递归处理逻辑:
        • 如果根节点不为空或还没找到,则递归处理
        • 左(看左子树能不能找到p或q)
        • 右(看右子树能不能找到p或q)
        • 中(对左右返回值的处理逻辑)
          • 如果左右不为空,说明左子树返回一个,右子树返回一个,则当前root为公共祖先;(对应情况1
          • 如果左为空而右不为空,说明右找到了一个或者直接找到公共祖先,返回右(反之亦然)(包含了情况2,当然也对情况1的处理也可能有此步骤)
          • 如果都为空,则返回空。
  • mark:之后再仔细看看 代码随想录中 关于返回值的描述。

    在递归函数有返回值的情况下:如果要搜索一条边,递归函数返回值不为空的时候,立刻返回,如果搜索整个树,直接用一个变量left、right接住返回值,这个left、right后序还有逻辑处理的需要,也就是后序遍历中处理中间节点的逻辑(也是回溯)。

    且代码随想录对本题的解析也很清晰,可以再读读。

  • 寻找最小公共祖先完整流程图如下:
    在这里插入图片描述

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

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

相关文章

nodejs+vue+ElementUi摄影作品图片分享工作室管理系统

第1周 2.21&#xff5e;2.27 查阅资料&#xff0c;学习vscode开发平台和vue框架技术 第2周 2.28&#xff5e;3.6 对软件功能需求进行分析, 软件功能模块划分及软件界面设计 第3周 3.7&#xff5e;3.13 撰写并提交毕业设计开题报告、英文资料翻译 第4周 3.14&#xff5…

[Linux] MySQL数据库之索引

一、索引的相关知识 1.1 索引的简介 索引是一个排序列表&#xff0c;包含索引值和包含该值的数据行的物理地址&#xff08;类似于 c 语言链表&#xff0c;通过指针指向数据记录的内存地址&#xff09;。 使用索引后可以不用扫描全表来定位某行的数据&#xff0c;而是先通过索…

Linux环境变量剖析

一、什么是环境变量 概念&#xff1a;环境变量&#xff08;environment variables&#xff09;一般是指在操作系统中用来指定操作系统运行环境的一些参数&#xff0c;是在操作系统中一个具有特定名字的对象&#xff0c;它包含了一个或多个应用程序所将使用到的信息&#xff0c…

excel统计分析——S-W正态性检验

参考资料&#xff1a; [1]马兴华,张晋昕.数值变量正态性检验常用方法的对比[J].循证医学,2014,14(02):123-128. 统计推断——正态性检验&#xff08;图形方法、偏度和峰度、统计&#xff08;拟合优度&#xff09;检验&#xff09;_sm.distributions.ecdf-CSDN博客 【统计学】…

Linux操作系统基础 – 修改文件权限

Linux操作系统基础 – 修改文件权限 Linux Operating System Essentials - Modify File Rights By JacksonML 文件是Linux操作系统存储信息的基本结构。文件是一组信息的集合。 在Linux操作系统和Windows操作系统相比较的最大不同&#xff0c;是Linux文件没有扩展名&#xff…

2023年全球前端大技术大会(GMTC北京站2023)-核心PPT资料下载

一、峰会简介 大会以“业务至上&#xff0c;效率为王”为主题&#xff0c;策划了 1 个主会场&#xff0c;10 个技术专场。会议议题包含前端 DevOps 实践、低代码、大前端监控、跨端技术选型、团队可持续发展、IoT 动态应用开发、移动端性能与效率优化、TypeScript、大前端技术…

等腰三角形两底角相等

等腰三角形定义: 是指至少有两边相等的三角形。相等的两个边称为这个三角形的腰 二.证明 有等腰△ABC,AB和AC是腰,p是BC的中点 证明等腰三角形两底角相等 即 ∠ A B P ∠ P C A ∠ABP∠PCA ∠ABP∠PCA ∴ ∴ ∴ 三角形内角和为180 ∵ { ∠ A B P ∠ A P B ∠ B A P 180 …

形态学处理

形态学处理的相关内容 &#xff08;1&#xff09;基于图像形态进行处理的一般方法 &#xff08;2&#xff09;这些处理方法基本是对二进制图像进行处理 &#xff08;3&#xff09;卷积核决定着图像处理后的结果 形态学图像处理 &#xff08;1&#xff09;腐蚀&#xff08;…

如何打包鸿蒙应用并发布到应用市场

知识点&#xff1a; HarmonyOS 应用打包后的文件为.app 格式&#xff0c; android 打包后的文件为.apk&#xff0c;IOS 打包后的文件为.apa HarmonyOS通过数字证书&#xff08;.cer文件&#xff09;和Profile文件&#xff08;.p7b文件&#xff09;等签名信息来保证应用的完整性…

最常见的SQL报错注入函数(floor、updatexml、extractvalue)及payload总结

SQL报错注入是一种常见的SQL注入攻击方式&#xff0c;攻击者通过注入恶意代码&#xff0c;触发数据库的错误响应&#xff0c;并从错误信息中获取有用的信息。 下面介绍最常见的三个报错注入函数用法及payload总结&#xff1a; 1、floor() 使用floor报错注入&#xff0c;需要…

VS2020使用MFC开发一个贪吃蛇游戏

背景&#xff1a; 贪吃蛇游戏 按照如下步骤实现:。初始化地图 。通过键盘控制蛇运动方向&#xff0c;注意重新设置运动方向操作。 。制造食物。 。让蛇移动&#xff0c;如果吃掉食物就重新生成一个食物&#xff0c;如果会死亡就break。用蛇的坐标将地图中的空格替换为 #和”将…

[动态规划]完全背包问题及其优化

题目描述 有N种物品和一个容量为 V 的背包&#xff0c;每种物品都有无限件可用。 第 i 种物品的体积是Ci&#xff0c;价值是Wi。求解在不超过背包容量的情况下&#xff0c;能够获得的最大价值。 输入 第一行为两个整数N、V(1≤N,V≤10000)&#xff0c;分别代表题目描述中的物…

java 怎么读取文件创建时间?

Java读取文件创建时间的实现方法 在工作时候&#xff0c;我们有时候需要获取到文件的最后更新时间&#xff0c;根据最近更新时间&#xff0c;来处理其他业务。那么&#xff0c;在Java中&#xff0c;怎么获取到文件最后更新时间呢&#xff1f;接下来凯哥(个人号&#xff1a;凯哥…

教你应对Github最新的2FA二次验证! 无地区限制, 你的Github账户可能被封禁!

文章目录 2FA 定义2FA验证方法1 硬件令牌2.推送通知3.SMS 验证4 基于语音的身份验证 解决方案安装身份验证器的谷歌浏览器插件打开 github 的二维码&#xff0c;直接扫描 2FA 定义 双因素身份验证 (2FA) 是一种身份和访管理安全方法&#xff0c;需要经过两种形式的身份验证才能…

大数据----MapReduce实现统计单词

目录 一、简介二、实现单词统计数据准备编程MapReduceJob 三、运行四、结果 一、简介 Hadoop MapReduce 是一个编程框架&#xff0c;它可以轻松地编写应用程序&#xff0c;以可靠的、容错的方式处理大量的数据(数千个节点)。 正如其名&#xff0c;MapReduce 的工作模式主要分…

每日一题——Leetcode908

方法一 数学思想&#xff1a; 其实就是看数组中最大值和最小值一个加上k一个减去k是否能刚好凑到0&#xff0c;如果不能就是两者之差 var smallestRangeI function(nums, k) {var min9999,max-1for(var i0;i<nums.length;i){min Math.min(min,nums[i])max Math.max(max…

Python数据分析 Matplotlib篇 基本方法初识 (第1讲)

Python数据分析 Matplotlib篇(第1讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

leetcode 1576. 替换所有的问号(easy)(优质解法)

链接&#xff1a;1576. 替换所有的问号 代码&#xff1a; class Solution {public String modifyString(String s) {char[] charSs.toCharArray();int lengthcharS.length;//遍历找到 &#xff1f;for(int i0;i<length;i){if(charS[i]?){//遍历 a ~ z 选择一个合适的字符来…

Linux怎么解压zip格式文件?

Linux解压命令zip是一种常见的文件压缩格式&#xff0c;用于把文件打包成一个zip文件&#xff0c;当我们需要共享或是发送时&#xff0c;能够更快速的发送&#xff0c;储存起来能够减少储存空间。那我们在Linux上怎么使用解压命令zip来解压zip格式文件呢&#xff1f;我们一起来…

MySQL 大数量left join 太慢语句拆分的一种办法

最近做点股市分析&#xff0c;发现日线数据已经达到了千万级&#xff0c;想做个两个日期之间的收盘价比较&#xff0c;例如第一周1月3日和1月6日的涨幅&#xff0c;很简单的语句&#xff0c;如下&#xff1a; select a.scode,s. name,a.sdate sdate1,a.close close1, b.sdate …