news 2026/4/18 12:00:25

LeetCode 235 236 最近公共祖先(LCA)解题总结

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 235 236 最近公共祖先(LCA)解题总结

目录

一、LeetCode 236. 普通二叉树的最近公共祖先

1. 核心思想:后序遍历 + 递归分治(验证式遍历)

2. 完整实现代码

3. 重点 & 难点

重点:递归返回值的 “信号含义”(核心!)

难点:

4. 深度分析

二、LeetCode 235. 二叉搜索树(BST)的最近公共祖先

1. 核心思想:有序性预判 + 单向递归(预判式遍历)

2. 完整实现代码

3. 重点 & 难点

重点:BST 有序性带来的 “剪枝” 优化

难点:

4. 深度分析

三、两道题的核心对比

四、通用易错点总结

1. 236 题高频易错点

2. 235 题高频易错点

3. 通用易错点

五、深度总结


最近公共祖先(LCA)是二叉树领域的经典高频题,LeetCode 236(普通二叉树的 LCA)和 235(二叉搜索树 BST 的 LCA)是同类型但解法差异极大的两道题 —— 核心差异源于 BST 的 “数值有序性”:235 可通过有序性 “预判 LCA 位置” 实现单向递归剪枝,236 无特性可利用,只能通过 “后序遍历 + 递归分治” 验证子树存在性。以下从核心思路、实现、重难点、深度分析等维度全面总结。

一、LeetCode 236. 普通二叉树的最近公共祖先

1. 核心思想:后序遍历 + 递归分治(验证式遍历)

普通二叉树无 “有序性” 等特殊性质,无法预判 LCA 位置,因此采用后序遍历的递归分治(先子后根):

  • 递归终止条件:遇到空节点(返回 null,子树无 p/q)、遇到 p/q(返回自身,找到目标节点);
  • 信号传递:递归左、右子树,获取 “左子树是否找到 p/q”“右子树是否找到 p/q” 的信号;
  • 分治合并:根据左右子树的信号,判断当前节点是否为 LCA。

2. 完整实现代码

class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // 终止条件1:空节点(子树无p/q,返回null) if (root == null) return null; // 终止条件2:找到p/q(自身是祖先,返回自身) if (root == p || root == q) return root; // 后序遍历:先处理左、右子树,获取信号 TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); // 分治合并逻辑 if (left != null && right != null) return root; // 左右都找到→当前是LCA return left != null ? left : right; // 单侧找到/都没找到(题目保证存在,后者仅子树出现) } }

3. 重点 & 难点

重点:递归返回值的 “信号含义”(核心!)

递归返回值不是直接返回 LCA,而是 “当前子树是否存在 p/q” 的信号:

返回值含义
null当前子树既无 p 也无 q
p/q当前子树仅找到 p 或仅找到 q
非 p/q 的节点当前子树同时找到 p 和 q(当前节点是 LCA)
难点:
  1. 为什么必须用后序遍历?只有先获取左、右子树的 “找到信号”,才能判断当前节点是否是 LCA—— 前序 / 中序遍历无法完成 “子树信号合并”,这是递归逻辑的唯一选择。
  2. 容易混淆 “返回 p/q” 和 “返回 LCA”:递归到 p 节点时返回 p,不是因为 p 是 LCA,而是告诉上层 “这侧找到了 p”;只有当左右子树都返回非 null 时,才确定当前节点是 LCA。

4. 深度分析

  • 时间复杂度:O (n)(n 为节点数)。普通二叉树无特性,最坏情况(斜树)需遍历所有节点;
  • 空间复杂度:O (h)(h 为树高)。递归调用栈深度 = 树高,平衡树 h=logn,斜树 h=n;
  • 核心逻辑本质:“自底向上” 的信号传递 —— 底层子树的 “找到信号” 向上汇总,直到某一层节点满足 “左右都找到”,该节点就是 LCA。

二、LeetCode 235. 二叉搜索树(BST)的最近公共祖先

1. 核心思想:有序性预判 + 单向递归(预判式遍历)

BST 的核心特性是 “左子树所有节点 < 根 < 右子树所有节点”,因此可通过数值比较直接预判 LCA 位置,无需遍历整棵树:

  • 若 p、q 都 < root.val:LCA 在左子树→仅递归左子树;
  • 若 p、q 都 > root.val:LCA 在右子树→仅递归右子树;
  • 其他情况(p≤root≤q 或 q≤root≤p,或 root=p/q):当前 root 就是 LCA→直接返回,递归终止。

2. 完整实现代码

class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { // 情况1:p/q都在左子树→递归左 if (p.val < root.val && q.val < root.val) { return lowestCommonAncestor(root.left, p, q); } // 情况2:p/q都在右子树→递归右 else if (p.val > root.val && q.val > root.val) { return lowestCommonAncestor(root.right, p, q); } // 情况3:其余情况→当前root是LCA else { return root; } } }

3. 重点 & 难点

重点:BST 有序性带来的 “剪枝” 优化

普通二叉树是 “验证式遍历”(遍历子树验证是否存在 p/q),而 BST 是 “预判式遍历”(通过数值比较直接定位 LCA 路径),遍历范围从 “整棵树” 缩减为 “根到 LCA 的单条路径”,时间复杂度从 O (n) 降至 O (h)(平衡 BST 下 O (logn))。

难点:
  1. 隐性的递归终止条件:题目保证 p/q 存在,因此递归不会遍历到空节点,终止条件藏在 “情况 3” 中(返回 root);新手易冗余添加if (root == null) return null,该判断无性能收益(永远不触发),仅提升工程健壮性。
  2. “其他情况” 的覆盖范围:不仅包含 “p/q 分属左右子树”,还包含 “root 是 p/q 其中一个”(节点可作为自身的祖先),漏考虑后者会导致逻辑错误。

4. 深度分析

  • 时间复杂度:O (h)(h 为树高)。仅遍历根到 LCA 的路径,无无效节点访问;
  • 空间复杂度:O (h)(递归栈深度 = 路径长度);
  • 迭代版优化(避免递归栈溢出)
    class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { while (true) { if (p.val < root.val && q.val < root.val) root = root.left; else if (p.val > root.val && q.val > root.val) root = root.right; else return root; } } }

三、两道题的核心对比

维度LeetCode 236(普通二叉树)LeetCode 235(BST)
核心思路后序遍历 + 递归分治(验证存在性)有序性预判 + 单向递归(定位位置)
递归终止条件显式(root==null /root==p/q)隐性(情况 3 返回 root)
遍历范围整棵树(最坏 O (n))根到 LCA 的路径(O (h))
关键依赖仅依赖二叉树递归结构依赖 BST 的数值有序性(核心)
分支逻辑合并左、右子树信号(3 种情况)数值比较预判方向(3 种情况)
代码复杂度中等(需理解信号传递)简单(仅数值比较)

四、通用易错点总结

1. 236 题高频易错点

  • 误解递归返回值:把 “返回 p/q” 当成 “返回 LCA”,忽略 “信号传递” 的本质;
  • 遗漏root == null终止条件:递归到空节点的子节点,触发空指针异常;
  • 分支逻辑错误:把 “左右都非 null 返回 root” 写成 “返回 left/right”,导致 LCA 判断错误;
  • 忽略 “节点可作为自身祖先”:比如 p 是 q 的祖先时,直接返回 p 即可,无需继续递归。

2. 235 题高频易错点

  • 冗余添加root == null判断:题目保证 p/q 存在,该判断永远不触发,无性能收益;
  • 数值比较逻辑错误:把 “p/q 都 < root” 写成 “p<root || q<root”(应为 &&),导致递归方向错误;
  • 混淆 “节点值” 和 “节点引用”:直接比较root == p而非root.val == p.val(题目中 p/q 是节点对象,需比较值);
  • 漏考虑 “root 是 p/q” 的场景:仅判断 “p/q 分属左右”,导致根节点为目标节点时返回错误。

3. 通用易错点

  • 对 LCA 定义的误解:忽略 “节点可作为自身的后代”,这是两道题的核心定义前提;
  • 递归栈溢出风险:斜树场景下 h=n,递归深度过大,可改用迭代版优化(236 迭代版需记录父节点,235 迭代版更简单)。

五、深度总结

LCA 问题的解题本质是 “利用树的结构 / 特性,最小化遍历范围”:

  1. 普通二叉树无特殊特性,只能通过 “后序遍历 + 信号传递” 验证子树存在性,是 “无特性时的通用解法”;
  2. BST 的有序性提供了 “数值预判” 的可能,将遍历范围从整棵树缩减到单条路径,是 “数据结构特性驱动算法优化” 的典型案例;
  3. 面试中,这两道题常作为 “递进式提问”:先问 235(BST),再追问 236(普通二叉树),核心考察 “是否能利用数据结构特性简化算法”“是否理解递归的信号传递逻辑”。

天气:🌧️

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/18 6:34:20

一口气讲明白网安工程师

一文讲透网络安全工程师与渗透测试&#xff1a;高薪职业解析&#xff0c;附200G免费教程&#xff0c;速速收藏&#xff01; 文章详细介绍了网络安全工程师的工作内容&#xff0c;包括防御系统设置&#xff08;防火墙、入侵检测系统&#xff09;和模拟黑客攻击的渗透测试&#…

作者头像 李华
网站建设 2026/4/18 6:34:54

无锡黑锋 HF44XX 45V高压、2μA超低静态电流、500mA极高PSRR LDO稳压器技术解析

一、芯片核心定位HF44XX 是一款在高压、低功耗、高电源纯净度与较强输出能力之间实现顶级平衡的线性低压差稳压器 其核心价值在于 45V的宽工作输入电压、业界领先的85dB1kHz超高PSRR、仅2μA的典型静态电流 以及 500mA的输出驱动能力 专为对电源噪声极度敏感且需要高压供电的汽…

作者头像 李华
网站建设 2026/4/18 6:35:32

02_软考_体系结构

计算机体系结构 体系结构分类 计算机指令 指令的寻址方式 指令系统 指令流水线 流水线的相关计算 加速比越大&#xff0c;流水线执行效率越高 存储系统 高速缓存cache cache与主存映射 cache命中率 主存编址 总线结构 系统可靠性分析

作者头像 李华
网站建设 2026/4/18 6:34:17

TM天微 TM1638 SOP28 数码管驱动

特性采用功率CMOS工艺显示模式10段8位键扫描&#xff08;83bit&#xff09;辉度调节电路&#xff08;占空比8级可调&#xff09;串行接口&#xff08;CLK&#xff0c;STB&#xff0c;DIO&#xff09;振荡方式&#xff1a;RC振荡&#xff08;450KHz5%&#xff09;内置上电复位电…

作者头像 李华
网站建设 2026/4/18 7:58:35

STC宏晶 STC8H1K16-36I-LQFP32 LQFP32 单片机

内核 超高速8051内核(1T)&#xff0c;比传统8051约快12倍以上 √指令代码完全兼容传统8051 √17个中断源&#xff0c;4级中断优先级 √支持在线仿真 工作电压 V 1.9V~5.5V √ 内建 LDO 工作温度 √-40℃~85℃(超温度范围应用请参考电器特性章节说明) Flash存储器 最大12K字节FL…

作者头像 李华
网站建设 2026/4/18 3:33:17

瑜伽馆管理系统的设计与实现(11471)

有需要的同学&#xff0c;源代码和配套文档领取&#xff0c;加文章最下方的名片哦 一、项目演示 项目演示视频 二、资料介绍 完整源代码&#xff08;前后端源代码SQL脚本&#xff09;配套文档&#xff08;LWPPT开题报告&#xff09;远程调试控屏包运行 三、技术介绍 Java…

作者头像 李华