235. 二叉搜索树的最近公共祖先 Medium
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p
、q
,最近公共祖先表示为一个结点 x
,满足 x
是 p
、q
的祖先且 x
的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
解题思路
输入:二叉搜索树(BST)的根节点 root
,以及两个指定节点 p
和 q
输出:返回这两个节点的最低公共祖先
本题适合利用二叉搜索树(BST)的性质结合自底向上的 DFS解决。由于是 BST,节点值满足 左子树 < 当前节点 < 右子树
的性质,可以高效判断 p
和 q
的位置。
我们可以归纳出以下 3 种情况:
- 如果
p
和q
的值分别位于当前节点值的两侧(一个小于,一个大于),则当前节点为最低公共祖先。 - 如果
p
和q
的值都小于当前节点值,说明它们都在左子树,最低公共祖先在左子树中,递归到左子树继续查找。 - 如果
p
和q
的值都大于当前节点值,说明它们都在右子树,最低公共祖先在右子树中,递归到右子树继续查找。
因此,我们通过比较当前节点值与 p
和 q
的值,利用 BST 性质快速定位子树方向,递归或直接返回最低公共祖先。
关键点:
- BST 的有序性使得我们无需完整遍历整棵树,只需根据节点值比较即可确定搜索方向。
- 找到最低公共祖先时,可能是
p
或q
本身(如果其中一个是另一个的祖先),或某个中间节点(p
和q
分居左右子树)。
分类讨论
│
├── 当前节点比 q 和 p 都小
│ └── 答案在左子树中
│
├── 当前节点比 p 和 q 都大
│ └── 答案在右子树中
│
├── 当前节点比 p 大,比 q 大
│ └── 当前节点就是答案
│
└──
代码实现
python
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 获取当前节点的值
x = root.val
# 如果 p 和 q 的值都小于当前节点值,说明都在左子树
# 递归到左子树继续寻找
if p.val < x and q.val < x:
return self.lowestCommonAncestor(root.left, p, q)
# 如果 p 和 q 的值都大于当前节点值,说明都在右子树
# 递归到右子树继续寻找
if p.val > x and q.val > x:
return self.lowestCommonAncestor(root.right, p, q)
# 如果一个节点在左子树,一个在右子树,或者当前节点是 p 或 q 之一
# 则当前节点就是最低公共祖先
return root
javascript
/**
* @param {TreeNode} root
* @param {TreeNode} p
* @param {TreeNode} q
* @return {TreeNode}
*/
var lowestCommonAncestor = function(root, p, q) {
const x = root.val;
if (p.val < x && q.val < x)
return lowestCommonAncestor(root.left, p, q);
if (p.val > x && q.val > x)
return lowestCommonAncestor(root.right, p, q);
return root;
};
复杂度分析
时间复杂度:O(n)
空间复杂度:O(h)