1.问题描述
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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。 因为根据定义最近公共祖先节点可以为节点本身
示例3
输入:root = [1,2], p = 1, q = 2 输出:1
提示
- 树中节点数目在范围
[2, 105]
内。 -109 <= Node.val <= 109
- 所有
Node.val
互不相同
。 p != q
p
和q
均存在于给定的二叉树中。
难度等级
中等
题目链接
2.解题思路
这道二叉树的最近公共祖先问题,说通俗点,就是找到一个共同的根节点或者是它们根节点的共同根节点。这里的第一步是找到p和q这两个节点,然后才来找共同的祖先,所以我们用到遍历方式是后序遍历。
首先,第一步是确定递归的结束条件,如果根节点为空,或者根节点就是p、q,那我们直接将节点返回即可。
//如果节点为空或者p、q其中一个,直接返回
if(root == null || root == p || root == q){
return root;
}
接着,我们就要来处理单层的递归逻辑。后序遍历的顺序是左右根,所以我们要分别调用递归方法获取当前根节点的左右节点的情况,从左右节点中看看能不能找到它们本身或者它们的祖先。
//左
TreeNode left = lowestCommonAncestor(root.left,p,q);
//右
TreeNode right = lowestCommonAncestor(root.right,p,q);
然后,根据左右节点的情况进行当前节点的处理。
情况一:如果左右节点都不为空,那说明左右节点可以找到p和q,所以根节点是它们的共同祖先,将根节点返回。
//根
//如果左右节点不为空,返回当前节点
if(left != null && right != null){
return root;
}
情况二:左右两个节点其中一个为空,另外一个不为空,那么不为空的那个节点,可以顺着下去找到p或者q或者pq的共同祖先,所以这时候,我们将不为空的那个节点返回即可。
//如果其中一个节点不为空,返回不为空的节点
if(left != null || right != null){
return left != null ? left : right;
}
情况三:左右两个节点都是空,直接返回空就好了。
//如果不是以上情况,返回空节点
return null;
3.代码展示
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//如果节点为空或者p、q其中一个,直接返回
if(root == null || root == p || root == q){
return root;
}
//左
TreeNode left = lowestCommonAncestor(root.left,p,q);
//右
TreeNode right = lowestCommonAncestor(root.right,p,q);
//根
//如果左右节点不为空,返回当前节点
if(left != null && right != null){
return root;
}
//如果其中一个节点不为空,返回不为空的节点
if(left != null || right != null){
return left != null ? left : right;
}
//如果不是以上情况,返回空节点
return null;
}
}
4.总结
这道题就是简单的考察了一下后序遍历和对最近共同祖先的理解,不是很难。这道题我就不啰嗦太多了,祝大家刷题愉快~