题目
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
一、代码实现
type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode
}func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {if root == nil || root == p || root == q {return root}left := lowestCommonAncestor(root.Left, p, q)right := lowestCommonAncestor(root.Right, p, q)if left != nil && right != nil {return root}if left != nil {return left}return right
}
二、算法分析
1. 核心思路
- 后序遍历:自底向上查找目标节点,通过递归返回值传递状态
- 状态判断:当某个节点的左右子树分别包含目标节点时,即为LCA
2. 关键步骤
- 递归终止:遇到空节点或目标节点立即返回
- 子树搜索:分别在左右子树中查找目标节点
- 结果合并:
- 左右子树均有返回值 → 当前节点为LCA
- 仅单侧有返回值 → 继续向上传递该结果
3. 复杂度
指标 | 值 | 说明 |
---|---|---|
时间复杂度 | O(n) | 每个节点遍历一次 |
空间复杂度 | O(h) | 递归栈空间,h为树的高度 |
三、图解示例
四、边界条件与扩展
1. 特殊场景验证
- 节点为根节点:返回根节点
- 节点互为祖先:返回层级更高的节点
- 节点不在树中:返回null(需预先验证)
2. 多语言实现
class Solution:def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':if not root or root == p or root == q:return rootleft = self.lowestCommonAncestor(root.left, p, q)right = self.lowestCommonAncestor(root.right, p, q)return root if left and right else left or right
class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {if (root == null || root == p || root == q) return root;TreeNode left = lowestCommonAncestor(root.left, p, q);TreeNode right = lowestCommonAncestor(root.right, p, q);return left != null && right != null ? root : left != null ? left : right;}
}
五、总结与扩展
1. 核心创新点
- 状态传递:利用递归返回值携带子树搜索信息
- 短路优化:发现目标节点后立即停止子树搜索
2. 扩展应用
- 多节点LCA:扩展算法处理多个目标节点
- 带父指针树:使用哈希表存储访问路径
- 频繁查询优化:结合RMQ算法预处理
3. 工程优化
- 迭代实现:用栈模拟后序遍历
- 路径记录:显式存储节点访问路径
- 输入验证:增加节点存在性检查