news 2026/9/24 23:57:48

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/9/25 0:46:09

SGMICRO圣邦微 SGM3204YN6G/TR SOT23-6 电荷泵

特性反转输入电源电压高达200mA输出电流输入电压范围1.4V至5.5V静态电流&#xff1a;1.5mA&#xff08;典型值&#xff09;950kHz开关频率集成有源肖特基二极管用于启动带载工作温度范围-40℃至85℃提供绿色SOT - 23 - 6封装

作者头像 李华
网站建设 2026/9/24 14:55:10

基于OA自动化办公系统的系统测试设计与实现

随着信息技术的飞速发展&#xff0c;OA自动化办公系统在各行各业得到了广泛应用&#xff0c;成为提升企业工作效率与管理水平的重要工具。然而&#xff0c;系统在开发完成后&#xff0c;其质量与稳定性仍需通过严格的测试来确保。因此&#xff0c;本文的研究内容聚焦于设计针对…

作者头像 李华
网站建设 2026/9/22 21:45:16

ETEK力芯微 ET7222 QFN10 单路双刀双掷模拟开关

功能特点 Vcc3.3V导通电阻典型值为6.0Q低位-位的抖动时间<50ps 低串扰:-45 dB 250 MHz 低电流消耗:1.0μA 接近于0的传输延迟: 250 ps通道导通时的电容: 4.0pF(Typical)工作电压范围:1.65V至4.5V >750 MHz带宽 封装:QFN10L-1.8*1.4(ET7222Y)、MSOP10(ET7222U)

作者头像 李华
网站建设 2026/9/24 7:10:47

爬虫自动化测试:Pytest + Allure 漂亮报告生成

在网络爬虫的开发与维护过程中&#xff0c;自动化测试是保障爬虫稳定性、可靠性的核心环节。而一份清晰、美观的测试报告&#xff0c;能帮助开发者快速定位问题、分析测试覆盖度。Pytest 作为 Python 生态中最流行的测试框架&#xff0c;以其简洁的语法和强大的扩展性著称&…

作者头像 李华
网站建设 2026/9/24 1:01:41

Llama-Factory是否支持命名实体识别(NER)任务?

Llama-Factory是否支持命名实体识别&#xff08;NER&#xff09;任务&#xff1f; 在大模型加速落地的今天&#xff0c;越来越多企业希望将通用语言模型应用于具体的信息抽取场景——比如从客服对话中提取客户姓名与电话、从医疗记录里识别疾病名称和用药信息。这类需求背后的核…

作者头像 李华
网站建设 2026/9/24 23:55:31

用ComfyUI做AI艺术创作:艺术家的真实使用体验分享

用ComfyUI做AI艺术创作&#xff1a;艺术家的真实使用体验分享 在AI生成图像已经泛滥的今天&#xff0c;真正让作品脱颖而出的&#xff0c;不再是“输入一段漂亮提示词”&#xff0c;而是你如何控制整个生成过程。我曾花整整三个月时间&#xff0c;在传统WebUI里反复调试参数、复…

作者头像 李华