题目:二叉树的最近公共祖先
题目链接:LeetCode-236. 二叉树的最近公共祖先
![在这里插入图片描述](https://img-blog.csdnimg.cn/f8de7e89295e4b1083cd1229ed02d836.png)
解法一:从根节点从上到下递归遍历找
思路分析
![在这里插入图片描述](https://img-blog.csdnimg.cn/74bf04223ba04f948e91a9e17a5e88cc.png)
- 如果p或者q就是root节点,则第一个公共父节点就是root,因为根据定义最近公共父节点可以是节点本身。(比如上图:p=3 q=8 或者 q=3 p=2)
- 如果递归到叶子节点了,但是还没有找到p或q,则直接返回nil,上层会再回溯判断的。
- 从根节点root往左右子树看,
1. 如果p q在同一侧,则可以直接放弃另一侧的递归查找,直接从同侧递归下去即可。(比如上图:p=5 q=7 或者 p=0 q=8)
2. 如果p q分布在两侧,则继续左右递归下去。(比如上图:p=5 q=0 或者 p=7 q=1)
复杂度:时间复杂度
O
(
n
)
O(n)
O(n)、空间复杂度
O
(
n
)
O(n)
O(n)
Go代码
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root == nil || root == p || root == q {
return root
}
if root.Left == nil && root.Right == nil {
return nil
}
left := lowestCommonAncestor(root.Left, p, q)
right := lowestCommonAncestor(root.Right, p, q)
if left != nil && right != nil {
return root
}
if left == nil {
return right
}
return left
}
解法二:从p、q节点向根节点方向遍历找第一个公共父节点
思路分析
- 先遍历所有子节点,将其的父节点找到,放入map中存储,方便之后直接从任一节点定位其父节点。
- 从p节点开始找他的所有父节点,并放入到p的父节点map中存储。
- 从q节点开始判断他的父节点是否在p的父节点map中存在,不存在就继续下一个父节点找,这样找到的第一个存在于p父节点map中的节点就是p和q的公共父节点。
- 如果最后都没有找到,说明p或者q不在该树中。
复杂度:时间复杂度
O
(
n
)
O(n)
O(n)、空间复杂度
O
(
n
)
O(n)
O(n)
Go代码
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if root == nil || root == p || root == q {
return root
}
parentMap := make(map[int]*TreeNode, 0)
pParentMap := make(map[*TreeNode]bool, 0)
// 把所有节点对应的父节点都找到
var findParent func(*TreeNode)
findParent = func(node *TreeNode) {
if node.Left != nil {
parentMap[node.Left.Val] = node
findParent(node.Left)
}
if node.Right != nil {
parentMap[node.Right.Val] = node
findParent(node.Right)
}
}
findParent(root)
// 找到p的所有父节点
for p != nil {
pParentMap[p] = true
p = parentMap[p.Val]
}
// 找到p和q的第一个公共父节点
for q != nil {
if pParentMap[q] {
return q
}
q = parentMap[q.Val]
}
return nil
}