LeetCode 235. 二叉搜索树的最近公共祖先
题目描述
给定一个二叉搜索树,找到该树中两个指定节点的最近公共祖先


题意分析
给定一棵二叉搜索树和其中两个不同节点
p、q,返回它们的最近公共祖先。公共祖先的子树中同时包含这两个节点,“最近”指所有公共祖先中深度最大的那个;一个节点也可以作为它自己的祖先。题目保证所有节点值唯一,并且
p、q都存在于树中。因此可以根据目标值与当前节点值的大小,判断目标位于左侧还是右侧。返回的是树中原有的节点引用,不是单独的节点值,也不是新建的同值节点。
解法:利用 BST 性质迭代下探
核心思路
[!blue]
从根节点开始,始终保持当前节点
cur的子树包含两个目标。根显然满足这个条件;之后只在能够确定两个目标同处某一侧时,才一起向这一侧下降。若
p.val和q.val都小于cur.val,由搜索树性质,它们都在左子树中。左孩子就是比当前节点更深的公共祖先候选,答案不必停在当前节点,可以令cur = cur.left。两个值都更大时,对称地进入右子树。如果两个目标分别位于当前节点两侧,那么它们从当前节点开始走向不同分支。任何更深节点只属于某一侧,不可能同时包含两个目标,因此当前节点就是最近公共祖先。
若
cur本身等于某个目标,另一个目标又在当前子树中,当前节点同样是公共祖先;其严格后代不可能再成为当前节点自己的祖先,所以也不能继续下降。代码用严格的小于和大于处理同侧情况,其余情况就同时覆盖了分叉与命中目标两种终止条件。整个过程是在追踪两条搜索路径的公共部分,只走一条向下路径,无需分别保存祖先列表或遍历无关子树。两个目标的参数顺序不影响判断,也不需要预设谁的值更小。
解题步骤
- 令游标
cur = root,当前子树包含两个目标。- 若两个目标值都小于当前值,进入左孩子。
- 若两个目标值都大于当前值,进入右孩子。
- 否则,当前节点是两条搜索路径的分叉点或其中一个目标,直接返回它。
代码实现
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
TreeNode cur = root;
while (cur != null) {
if (p.val < cur.val && q.val < cur.val) {
cur = cur.left;
} else if (p.val > cur.val && q.val > cur.val) {
cur = cur.right;
} else {
// 两个目标分处两侧,或当前节点就是其中一个目标时,返回当前节点。
return cur;
}
}
return null;
}
}
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
cur := root
for cur != nil {
if p.Val < cur.Val && q.Val < cur.Val {
cur = cur.Left
} else if p.Val > cur.Val && q.Val > cur.Val {
cur = cur.Right
} else {
// 分叉点或命中其中一个节点时就是最近公共祖先。
return cur
}
}
return nil
}
复杂度分析
- 时间复杂度:$O(h)$,
h为树高,每轮只进入一个孩子。平衡树为 $O(\log n)$,退化为链时最坏为 $O(n)$。- 空间复杂度:$O(1)$,只使用当前节点游标,没有递归栈或祖先列表。
关键点总结
[!green]
- 当前子树始终同时包含两个目标,同侧时才有更深的公共祖先可继续查找。
- 分处两侧或命中其中一个目标时,已经无法让两个目标同时落入更低的同一子树。
- 搜索树的唯一值与有序性,让数值比较能够代表节点所在方向。
易错点总结
[!yellow]
- 用逻辑或判断同侧,只要一个目标满足就下降,会把另一个目标丢在搜索范围外;两个条件必须同时成立。
- 假定
p.val < q.val,会使交换参数顺序后判断错误;应对两个值对称处理。- 命中一个目标后还继续向下,会错过目标节点本身就是最近公共祖先的情况。
- 找到分叉时返回最初的
root,而非当前的cur,会把更高的公共祖先当成最近的那个。- 将这套按值下探的规则直接用于普通二叉树,无法保证目标所在方向;本题依赖搜索树性质。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 236. 二叉树的最近公共祖先 | 中等 | 普通树不能按值判断两个目标在哪一侧,本题可利用BST性质沿单一路径下降。 |
| 700. 二叉搜索树中的搜索 | 简单 | 同样根据目标与当前值的关系选择子树,本题在两个目标分居两侧时停止。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!