§1
题目描述
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科 中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大( 一个节点也可以是它自己的祖先 )。” 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
root,p,q = [6,2,8,0,4,7,9,null,null,3,5],2,8
输出 = 6
§2
思路解析动画文字版
下面 9 步动画会按主解代码推进,而不是泛泛讲题型。
利用 BST 性质找分叉点:在 BST 里找 LCA 有捷径:利用「左小右大」,从根开始比大小,就能直接走向 p、q 的分叉点。先标出目标 p=2、q=8。
从根 6 比较 · 一左一右就分叉:从根 6 开始:p=2 比 6 小、在左边,q=8 比 6 大、在右边。它俩从这里分道扬镳——6 是最后一个「还把它们装在一起」的节点,也就是 LCA。
为什么「分叉点」就是 LCA:想清楚为什么:只要 p、q 还在同一侧,它们就还共享这棵子树的根;一旦在某节点分到两边,再往下就各走各的。那个「让它们第一次分开」的节点,就是最近公共祖先。
另一种情况 · 同侧就一起往下走:如果换一对目标、它俩都比当前小,就一起往左走;都比当前大就一起往右;反复缩小,直到它们在某节点一左一右分开(或正好撞上其中一个),那个节点就是答案。每步砍掉一半,O(h)。
记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
边界三连:BST 找 LCA 的边界:分叉立即停、撞上目标也停。
三个高频追问:和 LC236 的区别、判定条件、O(1) 空间。
§3
参考代码
class Solution: def lowestCommonAncestor(self, root, p, q): cur = root while cur: if p.val < cur.val and q.val < cur.val: cur = cur.left elif p.val > cur.val and q.val > cur.val: cur = cur.right else: return cur看懂代码不等于写得出。盖住上面,自己默写一遍试试。卡在哪一行说不清,就点右下角问小欧。
§4
复杂度
- 时间复杂度:O(h),沿树高向下
- 空间复杂度:O(1),迭代写法
§5
易错点
✗ 错误写法:当普通二叉树 LCA 做
✓ 正确写法:利用 BST 大小关系
可以只走一条路径
✗ 错误写法:分叉点不含等号
✓ 正确写法:当前节点等于 p 或 q 也可返回
一个节点可以是自己的祖先
§
面试追问把动画讲成自己的话
追问BST 找 LCA 和普通二叉树(LC236)有什么不同?
普通二叉树要后序遍历整棵树找分叉;BST 能利用「左小右大」直接顺着大小往下走,O(h) 时间、O(1) 空间,快得多。
追问怎么判断当前节点就是 LCA?
p、q 都比它小就往左、都比它大就往右;只要它俩分到两侧(或有一个等于当前节点),当前节点就是 LCA。
追问能做到 O(1) 空间吗?
能。迭代版只用一个指针从根往下走、不用递归栈,空间 O(1)。
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
下一题 · 树 8/23
→二叉树的层序遍历
LeetCode 102 · 中等 · 沿着 树 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
299道动画图解
37节语音讲解
28课数据结构
¥0.27折合 / 天
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
¥99 开通年卡 →
想成体系刷透这类套路?去图解算法专题