#236
中等
高频
递归法二叉树的最近公共祖先
这是一道围绕树、二叉树展开的高频练习。建议先掌握「递归法」这套写法,再结合下方步骤讲解理解状态维护、边界处理和复杂度取舍。
树
二叉树
题目分析
给你一棵二叉树和两个节点 p、q,要求找出它们最近的公共祖先。
所谓最近公共祖先,就是离这两个节点最近、并且同时位于它们上方的那个节点。一个节点也可以是它自己的祖先。
一句话概括:
在二叉树里,找出能同时覆盖 p 和 q 的最低那个节点。
接下来怎么看推荐代码: 带着这个理解再看推荐代码时,重点观察这条主线:递归在左右子树里找
p 和 q,如果两边都找到,当前节点就是最近公共祖先。推荐代码
推荐解法:递归法
时间复杂度: O(n)
空间复杂度: O(h)
核心思路: 递归在左右子树里找
p 和 q,如果两边都找到,当前节点就是最近公共祖先。public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 基本情况:如果根节点为空,或者根节点是p或q之一,则返回根节点
if (root == null || root == p || root == q) {
return root;
}
// 递归在左子树中查找
TreeNode left = lowestCommonAncestor(root.left, p, q);
// 递归在右子树中查找
TreeNode right = lowestCommonAncestor(root.right, p, q);
// 如果左子树中没有找到p或q,说明它们都在右子树中
if (left == null) {
return right;
}
// 如果右子树中没有找到p或q,说明它们都在左子树中
if (right == null) {
return left;
}
// 如果p和q分别在左右子树中,则当前根节点就是最近公共祖先
return root;
}结构化讲解
面试时怎么讲
开场思路
这题我会用递归,让每棵子树向上报告自己有没有找到 p 或 q。
核心过程
- 如果当前节点为空或等于
p/q,直接返回当前节点。 - 递归去左右子树分别寻找目标节点。
- 如果左右子树都返回非空,说明两个目标分布在两边,当前节点就是最近公共祖先。
- 否则返回非空那一边,把找到的信息继续向上传。
复杂度总结
时间复杂度 O(n),空间复杂度 O(h)。
面试补一句:这题面试里最重要的是把“递归返回值含义”先讲清楚。
核心思路
LCA 的关键是让递归返回“我这棵子树里有没有找到目标节点”。如果左右子树分别返回了一个目标,那么当前节点就是它们第一次汇合的位置。
步骤讲解
1
命中空节点或目标节点直接返回
如果当前节点为空,或当前节点正好是 p / q,直接把它返回给上层。
为什么这样做:递归需要把“找到目标”这件事向上传递。
对应代码提示:if (root == null || root == p || root == q) return root;
2
分别递归左右子树
向左、向右子树继续寻找 p 和 q。
为什么这样做:公共祖先可能在任意一侧,必须把两边结果都拿回来。
对应代码提示:TreeNode left = lowestCommonAncestor(root.left, p, q);
3
根据左右返回值合并结果
如果左右都非空,说明 p 和 q 分处两边,当前节点就是 LCA;否则返回非空那一边。
为什么这样做:最近公共祖先就是两个目标第一次分叉后向上汇合的节点。
对应代码提示:if (left != null && right != null) return root;
易错点
找到一个目标后就立刻结束整棵树
这样可能漏掉另一个目标在另一侧的信息。
正确理解:即使一侧找到,也要把另一侧递归结果拿回来再合并。
把“最近”理解成离根最近
实际上最近公共祖先是离两个节点都最近的公共节点,通常更靠下。
正确理解:判断标准是“第一次左右分开后重新汇合的位置”。
没理解递归返回值语义
如果不知道返回的是“找到的目标或祖先”,合并逻辑会很混乱。
正确理解:先明确:递归返回当前子树内找到的
p / q / LCA / null。复杂度与适用判断
时间复杂度:O(n)
空间复杂度:O(h)
比其他方案更好在哪里:比先找路径再比对更简洁,也更贴合树的递归结构。
适用判断:树上只要涉及两个节点的祖先关系、汇合点、分叉点,优先考虑 DFS 递归返回信息。
额外提醒
- 左右都非空时,当前节点就是答案。
动画演示
如果你还没完全看懂,可以展开动画演示。
递归法动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
递归法动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
二叉树的最近公共祖先
递归栈:
栈为空
查找状态:
找到节点P:否
找到节点Q:否
最近公共祖先:未找到
动画演示仅在桌面端提供,移动端请优先阅读推荐代码与结构化讲解。