100道面试必会算法-21-二叉树的最近公共祖先
题目描述
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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
解题思路
个人思路:
- 首先想到的是深度搜索,然后回溯上一层,记录路径,最后再对比两个路径数组,然后找到共同祖先,可行,但有太多计算。
正解:
传送门:https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/solutions/240096/236-er-cha-shu-de-zui-jin-gong-gong-zu-xian-hou-xu/
解题思路:
祖先的定义: 若节点 p
在节点 root
的左(右)子树中,或 p=root
,则称 root
是 p `的祖先。
最近公共祖先的定义: 设节点 root
为节点 p,q
的某公共祖先,若其左子节点 root.left
和右子节点 root.right
都不是 p,q
的公共祖先,则称 root
是 “最近的公共祖先” 。
根据以上定义,若 root
是 p,q
的 最近公共祖先 ,则只可能为以下情况之一:
p
和 q
在 root
的子树中,且分列 root
的 异侧(即分别在左、右子树中);
p=root
,且 q
在 root
的左或右子树中;
q=root
,且 p
在 root
的左或右子树中;
考虑通过递归对二叉树进行先序遍历,当遇到节点 p
pp 或 q
qq 时返回。从底至顶回溯,当节点 p,q
在节点 root
的异侧时,节点 root
即为最近公共祖先,则向上返回 root
。
代码
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;
}
}