LeetCode 236. 二叉树的最近公共祖先(LCA)
📌 题目链接
💡 解题思路
本题要求在一棵 普通二叉树 中找到两个节点 p 和 q 的 最近公共祖先(LCA)。
最近公共祖先定义 :
对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足:
- x 是 p 和 q 的祖先
- x 的深度尽可能大(离 p、q 最近)
🌳 核心思想:后序遍历(自底向上)
这是一道非常经典的 后序遍历(Left → Right → Root) 题目。由于是普通二叉树,无法利用大小关系剪枝,因此采用 后序遍历(左右根)。 只有当左右子树的递归结果都已知时,才能判断当前节点是否为最近公共祖先。
递归逻辑
对于当前节点 root:
-
递归终止条件
- 如果
root == null,返回null - 如果
root == p或root == q,直接返回root(不再向下递归)
- 如果
-
递归左右子树
javaTreeNode l = lowestCommonAncestor(root.left, p, q); TreeNode r = lowestCommonAncestor(root.right, p, q); -
根据左右返回值判断结果
- ✅ 左右都不为空 →
root就是 LCA - ✅ 左不为空,右为空 → 返回左
- ✅ 右不为空,左为空 → 返回右
- ❌ 都为空 → 返回
null
- ✅ 左右都不为空 →
🧠 为什么这样是对的?
情况一:p 和 q 分别在左右子树
root
/ \
p q
l != null,r != null- 只有
root能同时看到它们 - ✅ 返回
root
情况二:p 是 q 的祖先(或反过来)
p
\
q
- 递归到
p时直接返回 - 上层不会再找到第二个节点
- ✅ 返回
p
情况三:只在一个子树中
- 另一个子树返回
null - 直接返回非空的那个结果
🧩 完整代码(Java)
java
/**
* Definition for a binary tree node.
*/
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 1. 递归终止条件
if (root == null) return null;
if (root == p || root == q) return root;
// 2. 递归左右子树
TreeNode l = lowestCommonAncestor(root.left, p, q);
TreeNode r = lowestCommonAncestor(root.right, p, q);
// 3. 根据左右结果判断
if (l != null && r != null) return root; // p、q 分布在两侧
if (l == null && r != null) return r;
if (l != null && r == null) return l;
return null;
}
}
⏱ 复杂度分析
| 指标 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 每个节点最多访问一次 |
| 空间复杂度 | O(h) | 递归栈深度,h 为树高 |
- 最坏情况(链状树):
O(n) - 平衡二叉树:
O(log n)
🔍 常见误区
| 误区 | 正确理解 |
|---|---|
| 必须先找 p 再找 q | ❌ 顺序无关 |
| 必须记录父节点 | ❌ 递归天然回溯 |
| 只适用于 BST | ❌ 本题是普通二叉树 |
| 返回第一个遇到的节点 | ❌ 要看左右子树结果 |
✅ 总结一句话
后序遍历 + 左右返回值判断,是二叉树 LCA 问题的通用解法。