算法 - 二叉树的最近公共祖先 (LCA)
1. 题目
给定一个二叉树,找到树中两个指定节点 p、q 的最近公共祖先(Lowest Common Ancestor)。
最近公共祖先定义:对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。
示例:
1 | 3 |
2. 解题思路
2.1 通用二叉树:后序递归(最优)
自底向上。定义 lca(root, p, q) 返回「以 root 为根的子树中,p 和 q 的最近公共祖先或其中之一」。
对当前节点:
base case:
root为空,或root === p或root === q,直接返回root。递归左右子树得到
left、right。分类讨论:
left和right都非空 → p、q 分居两侧,当前root即为 LCA。- 只有一侧非空 → 说明两节点都在那一侧(或找到一个就把它返回),返回那侧的结果。
- 都空 → 返回
null。
时间复杂度:
O(n)。空间复杂度:
O(h)递归栈。
2.2 若是二叉搜索树(BST 235 题)
利用有序性:从根开始,p、q 都小于当前值走左、都大于走右,一旦分裂或等于即为 LCA,无需递归,O(h) 时间 O(1) 空间。
3. TypeScript 实现
1 | function lowestCommonAncestor( |
4. 面试延伸
- 理解「一个节点是自身祖先」:所以 p 是 q 的祖先时,LCA 就是 p,这正是 base case 命中
root === p后直接返回的原因。 - 若 p、q 不一定存在? 需要额外标记是否都找到,或用父指针法(记录路径再比对)。
- 多叉树 LCA / 带 parent 指针的 LCA(相交链表思路):把两条到根的路径当作「找第一个公共节点」,与 [相交链表] 同源。
- 递归返回值的语义要讲清:它同时承担了「找到一个就上报」和「两侧都命中就在根结算」两种职责,是本题最精妙处。
难度:中等 | LeetCode 236 题 | 后序递归经典