题目来源:LeetCode235:二叉搜索树的最近公共祖先
问题抽象: 给定一个二叉搜索树(BST)的根节点 root 和树中两个节点 p、q,要求找到 p 和 q 的 最近公共祖先(LCA) 节点(即深度最大的共同祖先),需满足以下核心需求:
-
LCA 定义:
- 祖先关系:节点
x是p和q的祖先需满足:p和q均在x的子树中(或x=p或x=q);
- 最近性:
x是所有满足条件的节点中深度最大者(离p和q最近)。
- 祖先关系:节点
-
输入约束:
- 节点数
∈ [2, 10^4](保证p和q存在且不同); - 节点值唯一(含负整数),且满足 BST 性质(左子树值
<根值<右子树值); p和q为树中实际存在的节点(非值拷贝)。
- 节点数
-
BST 特性利用:
- 值比较替代路径搜索:根据
p.val、q.val与当前节点值的相对位置确定 LCA 方向:- 若
p.val和q.val小于 当前节点值 → LCA 在左子树; - 若
p.val和q.val大于 当前节点值 → LCA 在右子树; - 否则当前节点即为 LCA。
- 若
- 值比较替代路径搜索:根据
-
计算要求:
- 时间复杂度 O(h)(
h为树高,最坏O(n)当树退化为链表); - 空间复杂度 O(1)(迭代实现,仅用指针遍历);
- 禁止存储父指针或额外路径空间。
- 时间复杂度 O(h)(
-
边界处理: 自身为祖先:若
p是q的祖先(或反之),则p(或q)即为 LCA
输入:BST 根节点 root;树中节点 p 和 q(p ≠ q)。
输出:节点(p 和 q 的最近公共祖先)。
解题思路
核心思路:利用二叉搜索树的性质(左子树所有节点值 < 根节点值 < 右子树所有节点值):
- 从根节点开始遍历:
- 若当前节点值同时大于
p和q的值,说明最近公共祖先在左子树,继续向左遍历。 - 若当前节点值同时小于
p和q的值,说明最近公共祖先在右子树,继续向右遍历。 - 否则,当前节点即为最近公共祖先(包括两种情况):
p和q分别在当前节点的两侧。- 当前节点是
p或q之一(符合“节点可以是自身祖先”的定义)。
- 若当前节点值同时大于
- 迭代优化:使用循环代替递归,避免栈空间开销,降低内存消耗。
时间复杂度:O(h),其中 h 是树的高度。
空间复杂度:O(1),仅使用常数级额外空间。
代码实现(Java版)🔥点击下载源码
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 确保 p 是较小节点,q 是较大节点,简化后续比较
int minVal = Math.min(p.val, q.val);
int maxVal = Math.max(p.val, q.val);
// 从根节点开始迭代
TreeNode current = root;
while (current != null) {
if (current.val > maxVal) {
// 当前值大于 maxVal,说明 p 和 q 都在左子树
current = current.left;
} else if (current.val < minVal) {
// 当前值小于 minVal,说明 p 和 q 都在右子树
current = current.right;
} else {
// 当前节点值在 [minVal, maxVal] 区间内,即为最近公共祖先
break;
}
}
return current;
}
}
代码说明
- 初始化:
通过minVal和maxVal确定p和q的值区间,避免后续重复比较。 - 迭代过程:
- 若当前节点值大于
maxVal,向左子树移动(p和q均在左子树)。 - 若当前节点值小于
minVal,向右子树移动(p和q均在右子树)。 - 否则,当前节点值在区间内,即为结果。
- 若当前节点值大于
- 终止条件:
循环结束时current指向最近公共祖先节点。
提交详情(执行用时、内存消耗)

870

被折叠的 条评论
为什么被折叠?



