news 2026/5/12 7:59:46

【码道初阶】【LeetCode 236】二叉树最近公共祖先:我是如何用几行递归搞定这个面试高频题的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【码道初阶】【LeetCode 236】二叉树最近公共祖先:我是如何用几行递归搞定这个面试高频题的?

【LeetCode 236】二叉树最近公共祖先:我是如何用几行递归搞定这个面试高频题的?

在二叉树的面试题中,“最近公共祖先”(Lowest Common Ancestor,简称 LCA)绝对是出现频率最高的题目之一。

初看题目,可能觉得有点绕:既要是祖先,深度还要尽可能大。但其实,只要我们转换一下视角,用后序遍历(自底向上)的思维去理解,这道题的代码逻辑简直优雅得让人惊叹。

今天,我就结合我写的这段 Java 代码,带大家像剥洋葱一样拆解这道题的递归思路。

1. 核心思维:把“寻找”变成“汇报”

解决这道题,我的核心策略是**“自底向上汇报”**。

你可以把每一个节点想象成一个部门经理。题目要求我们在整棵树里找pq
作为根节点(大老板),我不知道pq在哪,但我可以派我的左右手(左子树和右子树)去搜。

  • 我对左孩子说:“你去你的辖区找找,有没有p或者q?只要看到其中一个,就赶紧告诉我。”
  • 我对右孩子说:“你也去你的辖区找找,同上。”
  • 等他们回来汇报结果后,我再根据情况做判断。

这就是后序遍历的精髓:先搜左右,最后再处理根节点的逻辑。

2. 代码深度拆解

让我们看着代码,一行一行来翻译我的“内心戏”。

classSolution{publicTreeNodelowestCommonAncestor(TreeNoderoot,TreeNodep,TreeNodeq){if(root==null)returnroot;if(root==p||root==q)returnroot;TreeNodeleftTree=lowestCommonAncestor(root.left,p,q);TreeNodeRightTree=lowestCommonAncestor(root.right,p,q);if(leftTree!=null&&RightTree!=null){returnroot;}elseif(leftTree!=null){returnleftTree;}else{returnRightTree;}}}

第一步:终止条件(遇到死胡同或找到目标)

if(root==null)returnroot;// 或者 return nullif(root==p||root==q)returnroot;

这是递归的**“触底反弹”**时刻。当我走到当前节点root时,我有两个理由停止向下搜索:

  1. 到了空节点(root == null):这里啥也没有,死胡同,返回null(代码中写return root也是返回 null)。
  2. 找到了目标(root == p 或 root == q):这里有一个关键点!如果我发现当前节点就是p或者q,我不需要再往下找了。直接把我自己(root)返回上去。
    • 潜台词:“报告长官,我在这个位置发现了嫌疑人 P(或者 Q)!”

第二步:下发任务(递归搜索)

TreeNodeleftTree=lowestCommonAncestor(root.left,p,q);TreeNodeRightTree=lowestCommonAncestor(root.right,p,q);

这两行代码就是“派人出去搜”。

  • leftTree存的是左那边搜寻的结果。
  • RightTree存的是右那边搜寻的结果。

注意,递归函数会一直钻到底,直到触发第一步的终止条件,才会带着结果一层层返回。

第三步:汇总决策(我是不是祖先?)

这是整段代码的灵魂,也是很多人容易晕的地方。我现在拿到了左右手下的汇报结果leftTreeRightTree,现在我要通过这三个if-else来判断情况:

情况 A:左右都有发现 -> 我就是 LCA

if(leftTree!=null&&RightTree!=null){returnroot;}

如果leftTree不为空(说明左边找到了一个),而且RightTree也不为空(说明右边也找到了一个)。
这意味着什么?意味着pq分别在我的左边和右边。
既然一个在左一个在右,那我不就是他们相遇的那个分岔路口吗?
所以我就是那个最近公共祖先!直接返回我自己(root)。

情况 B:只有左边有发现 -> 结果在左边

elseif(leftTree!=null){returnleftTree;}

如果左边回报说“找到了”,而右边回报说“全是 null”。
说明pq都在我的左子树里(或者其中一个在左边,另一个根本不在树里,但题目保证一定在)。
既然都在左边,那我这个“当前节点”就不是最近的祖先,真正的结果是左手汇报上来的那个节点。于是我做个顺水人情,把leftTree继续往上传递。

情况 C:只有右边有发现(或都为 null) -> 结果在右边

else{returnRightTree;}

同理,如果左边是空的,那结果一定在右边。直接把RightTree返回上去。

3. 一个特殊的疑问:如果一个节点是另一个的祖先怎么办?

有同学可能会问:“如果p5q1,而结构是5 -> ... -> 1,你的代码会先遇到5就直接返回了,不会去搜下面的1吗?”

你是对的,但这正是代码巧妙的地方!

回顾一下终止条件:if(root == p || root == q) return root;

如果我先遇到了p(比如节点 5),我直接返回5。我根本不会去遍历5的子树,所以我也不会去刻意找q
但在这种情况下,p本身就是pq的最近公共祖先。
所以,直接返回p是完全正确的逻辑!代码自动涵盖了“一个节点是另一个节点祖先”的特殊情况。

4. 总结

这段代码虽然短,但逻辑非常严密:

  1. 遇到 null-> 返回 null。
  2. 遇到 p 或 q-> 返回当前节点(找到了)。
  3. 左搜右搜-> 拿到左右结果。
  4. 左有且右有-> 当前节点就是答案(LCA)。
  5. 一边有一边无-> 答案在有结果的那一边。

这就是利用二叉树后序遍历解决 LCA 问题的全部奥秘。与其死记硬背,不如想象成一个“下属汇报、上级决策”的过程,是不是瞬间清晰了很多?

希望这篇博客能帮你彻底拿下这道 LeetCode 高频题!

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

Git入门学习

Git:分布式管理系统(存档)1. Your Identity 配置你的信息git config --global user.name "827dls"git config --global user.email 1670704430qq.com红色部分表示对第二个存档进行修改 非常直观上传GitHub查看提交日志 : git log

作者头像 李华
网站建设 2026/5/8 19:34:23

项目实战05—XXX火力发电厂工业蒸汽量预测

火力发电是一种很常用的发电技术,但是火力发电的转换效率并不高。其中蒸汽压力的高低直接关系到火力发电的效率,火力发电的效率与蒸汽的压力之间的关系并不是正相关关系。 火力发电过程要尽量使水处在蒸发的临界状态,这时火力发电的效率最高。因此,火力发电厂需要及…

作者头像 李华
网站建设 2026/5/12 3:26:04

在职备战法考,先择校还是先备考?

许多在职考生都听过一个建议:“别想太多,先学起来。”于是,你匆忙找来资料,埋头苦学两月,却越发感到方向模糊、效率低下、坚持困难……这时你可能才意识到:在错误的道路上“先出发”,往往意味着…

作者头像 李华
网站建设 2026/5/11 12:28:41

AgentScope x RocketMQ:打造企业级高可靠 A2A 智能体通信基座

作者:琛琪、稚柳 引言 Agentic AI 时代已至,在智能客服、代码生成、流程自动化等场景中,多智能体(Multi-Agent)协作正从构想走向落地。然而,当多个 Agent 需要像一个团队那样高效协作时,脆弱的…

作者头像 李华
网站建设 2026/5/9 7:49:53

2025年夸克网盘新用户送1T 空间,免费领取!

一、活动时间 2025年01月01日 ~ 2025年12月31日 二、面向用户 夸克 App 新用户,即在手机端和 PC 端从未使用手机号注册过夸克账号的用户 只安装过夸克客户端但从未注册夸克账号的用户,也可获得本次新用户活动奖励; 如果用户使…

作者头像 李华
网站建设 2026/5/10 8:14:42

PDF24 Creator PDF 工具箱 v11.29.0

可将大部分文件转成pdf格式的免费软件,安装好后会在你的 打印机 里看到一个叫PDF24的虚拟打印机,你可将要转成pdf格式的文件打印时选虚拟打印机PDF24,也可以直接将文件以拖拉方式拉进这软件的主视窗编辑区里,它会自动转成pdf格式&…

作者头像 李华