给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。
示例 2:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出: 5
解释: 节点 5 和节点 4 的最近公共祖先是节点 5。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
解题思路
这是Leetcode 235:二叉搜索树的最近公共祖先(最详细的解法!!!)的推广。树型问题首先考虑递归,对于每个树中的p
和q
只会有一下几种情况
p
在左子树中,q
在右子树中q
在左子树中,p
在右子树中p
和q
都在左子树中p
和q
都在右子树中
对于第一种和第二种情况很简单,p
和q
的最近公共祖先就是root
。对于第三种情况我们只需递归向左子树找,第四种情况我们只需递归向右子树找。接着思考边界情况。
当p==root or q==root
的时候,我们返回root
即可(因为要找最近公共祖先,继续遍历的话,就不可能是其祖先了)。那么这里就有一个迷惑人的地方了,请认真思考第一种和第二种情况下,左右子树的递归返回结果是什么?就是p
和q
。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right:
return root
return left if left else right
同样递归可以解决的问题,我们都应该思考一下通过迭代怎么去做?思路非常简单,先通过层序遍历得到p
和q
的祖先节点。然后将p
的所有祖先放到集合ans
中去。接着判断q
的父亲节点是不是在ans
中,如果不在,继续判断q
父亲的父亲,不断向上,知道其中一个祖先在ans
中出现。那么这个出现的节点即为p
和q
的最近公共祖先。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
s, parent = [root], {root: None}
while p not in parent or q not in parent:
node = s.pop()
if node.left:
parent[node.left] = node
s.append(node.left)
if node.right:
parent[node.right] = node
s.append(node.right)
ans = set()
while p:
ans.add(p)
p = parent[p]
while q not in ans:
q = parent[q]
return q
还有一种不错的思路就是借助Leetcode 160:相交链表(超详细的解法!!!)中的思想。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
s, parent = [root], {root: None}
while p not in parent or q not in parent:
node = s.pop()
if node.left:
parent[node.left] = node
s.append(node.left)
if node.right:
parent[node.right] = node
s.append(node.right)
n1, n2 = p, q
while n1 != n2:
n1 = parent[n1] if n1 else q
n2 = parent[n2] if n2 else p
return n1
我将该问题的其他语言版本添加到了我的GitHub Leetcode
如有问题,希望大家指出!!!