236. 二叉树的最近公共祖先
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两节点在树中的关系为如下三种:
(1) q位于p祖先的左分支.(互换pq也成立)
{p/q}
/
/
/
{q/p}
(2) q位于p祖先的右分支.(互换pq也成立)
{p/q}
\
\
\
{q/p}
(3) p,q分布在祖先的不同分支上
{parent}
/ \
/ \
/ \
{p/q} {q/p}
所以, p, q只有如上三种关系,
对于(1) + (2), 我们判断某个节点是否在另外一个节点的上一层次,如果是,那么上层节点肯定就是下层节点的祖先.
if (p->left == q or p->right == q or p == root )
return p;
if (q->left == p or q->right == p or q == root )
return p;
对于(3),公共祖先就是root,无论p,q分别分布于左右分支的节点的路径分别有多长.但是,如何寻找到这种关系呢?
当我们无法确定两个节点p,q 位于当前root节点的的同一个分支还是不同分支, 因此我们需要进行递归判断, 不仅要判断左边分支, 还要判断右边分支.
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) {
return root;
}
return left?left:right;
即,我们从root节点进入,发现我们的两个节点分别分布于两个分支下,那么我们就可以得知,root节点一定为最近公共祖先节点.
3.代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (not root)
return nullptr;
if (p->left == q || p->right == q || p == root) {
return p;
}
if (q->left == p || q->right == p || q == root) {
return q;
}
TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (left && right) {
return root;
}
return left?left:right;
}
};