最近公共祖先问题
LeetCode236.给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,对于下面的二叉树:
示例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 。因为根据定义最近公共祖先节点可以为节点本身。
递归解析:
- 终止条件:
- 当越过叶节点,则直接返回
null
; - 当
root
等于p,q
,则直接返回root
;
- 当越过叶节点,则直接返回
- 递推工作:
- 开启递归左子节点,返回值记为
left
; - 开启递归右子节点,返回值记为
right
;
- 开启递归左子节点,返回值记为
- 返回值: 根据
left
和right
,可展开为四种情况;- 当
left
和right
同时为空 :说明root
的左 / 右子树中都不包含p,q
,返回null
; - 当
left
和right
同时不为空 :说明p,q
分列在root
的 异侧 (分别在 左 / 右子树),因此root
为最近公共祖先,返回root
; - 当
left
为空 ,right
不为空 :p,q
都不在root
的左子树中,直接返回right
。具体可分为两种情况:p,q
其中一个在root
的 右子树 中,此时right
指向p
(假设为p
);p,q
两节点都在root
的 右子树 中,此时的right
指向 最近公共祖先节点 ;
- 当
left
不为空 ,right
为空 :与情况3
. 同理;
- 当
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) {
//只要当前根节点是p和q中的任意一个,就返回(因为不能比这个更深了,再深p和q中的一个就没了)
return root;
}
//根节点不是p和q中的任意一个,那么就继续分别往左子树和右子树找p和q
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
//p和q都没找到,那就没有
if(left == null && right == null) {
return null;
}
//左子树没有p也没有q,就返回右子树的结果
if (left == null) {
return right;
}
//右子树没有p也没有q就返回左子树的结果
if (right == null) {
return left;
}
//左右子树都找到p和q了,那就说明p和q分别在左右两个子树上,所以此时的最近公共祖先就是root
return root;
}
}