GitHub_Trending/leetcode1/leetcode二叉树的最近公共祖先:递归的回溯判断
【免费下载链接】leetcode Leetcode solutions 项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode
1. 问题本质与核心挑战
二叉树的最近公共祖先(Lowest Common Ancestor,LCA)问题是面试高频算法题,本质是寻找两个目标节点在树中最深的共同祖先节点。该问题在不同树结构下有显著差异:
- 二叉搜索树(BST):可利用节点值大小关系实现O(h)时间复杂度(h为树高)
- 普通二叉树:需通过后序遍历实现回溯判断,同样保持O(n)时间复杂度
本文将以GitHub_Trending/leetcode1/leetcode项目中的实现为基础,系统讲解两种场景下的递归解法。
2. 二叉搜索树(BST)的LCA解法
2.1 问题特性与关键洞察
BST的左子树节点值均小于根节点,右子树节点值均大于根节点。这一特性使LCA判断可通过以下规则实现:
- 若两目标节点值均大于当前节点值,LCA必在右子树
- 若两目标节点值均小于当前节点值,LCA必在左子树
- 否则当前节点即为LCA(包含一个节点是另一个祖先的情况)
2.2 C语言实现代码深度解析
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val; // 节点值
* struct TreeNode *left; // 左子节点指针
* struct TreeNode *right; // 右子节点指针
* };
*/
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
// 提取当前节点及目标节点值
int rootVal = root->val;
int pVal = p->val;
int qVal = q->val;
// 两节点均在右子树
if (pVal > rootVal && qVal > rootVal) {
return lowestCommonAncestor(root->right, p, q);
}
// 两节点均在左子树
else if (pVal < rootVal && qVal < rootVal) {
return lowestCommonAncestor(root->left, p, q);
}
// 当前节点即为LCA
return root;
}
2.3 执行流程可视化
2.4 边界情况处理
| 场景 | 算法行为 | 示例 |
|---|---|---|
| 一个节点是另一个的祖先 | 返回祖先节点 | p是q的父节点时返回p |
| 节点值相等 | 直接返回当前节点 | 处理重复值BST时仍有效 |
| 树退化为链表 | 自动转为线性查找 | 保持O(n)时间复杂度 |
3. 普通二叉树的LCA解法
3.1 问题差异与解决方案
普通二叉树无节点值大小关系特性,需通过后序遍历实现:
- 递归查找左子树是否包含p或q
- 递归查找右子树是否包含p或q
- 若当前节点满足以下条件之一则为LCA:
- 左子树和右子树各包含一个目标节点
- 当前节点是目标节点之一且子树包含另一节点
3.2 Go语言实现代码解析
/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *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
}
3.3 递归回溯过程可视化
4. 两种算法的复杂度对比
| 算法类型 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| BST递归 | O(h) | O(h) | 有序二叉树,值唯一 |
| 普通二叉树递归 | O(n) | O(h) | 任意二叉树结构 |
注:h为树的高度,平衡树时h=logn,最坏情况(链表)h=n
5. 实战应用与扩展思考
5.1 算法优化方向
- 迭代实现:将递归转为栈实现,避免递归栈溢出风险
- 路径记录法:分别记录根到两节点路径,比较路径找LCA
- 父指针法:通过哈希表存储节点父指针,类似链表相交问题
5.2 常见错误与避坑指南
- 空指针处理:必须先判断root==nil再访问成员
- 基准条件设置:正确处理"当前节点是目标节点"的情况
- 后序遍历顺序:确保先处理左右子树再判断当前节点
5.3 面试高频变形题
- 二叉树中两个节点的距离:LCA到两节点距离之和
- N叉树的LCA:扩展子节点查找逻辑到多叉场景
- 含父指针的LCA:转化为求链表第一个公共节点
6. 总结与学习建议
LCA问题是理解树递归遍历的经典案例,掌握后可迁移解决多种树相关问题。建议学习路径:
- 从BST的LCA入手,理解利用树特性优化的思路
- 掌握普通二叉树的后序遍历解法,体会回溯思想
- 通过迭代实现加深对递归过程的理解
- 尝试解决变形问题巩固知识点
GitHub_Trending/leetcode1/leetcode项目中提供了多种语言实现,建议对比学习不同语言的语法特性对算法实现的影响。
来源:GitHub_Trending/leetcode1/leetcode项目
代码路径:c/0235-lowest-common-ancestor-of-a-binary-search-tree.c
更多解法:go/0236-lowest-common-ancestor-of-binary-tree.go
【免费下载链接】leetcode Leetcode solutions 项目地址: https://gitcode.com/GitHub_Trending/leetcode1/leetcode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



