给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 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
均存在于给定的二叉树中。
解法一:递归
/**
* 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* ans;
bool dfs(TreeNode* root ,TreeNode* p,TreeNode* q){
if(root==NULL)
return false;
bool lson=dfs(root->left,p,q);
bool rson=dfs(root->right,p,q);
if((lson&&rson)||((lson||rson)&&(root->val==q->val||root->val==p->val)))
ans=root;
return lson||rson||(root->val==p->val)||(root->val==q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root,p,q);
return ans;
}
};
这段代码实现了在二叉树中找到两个节点的最近公共祖先节点。
-
首先定义了一个成员变量
ans
,用来存储最近公共祖先节点的指针。 -
然后定义了一个递归函数
dfs
,用来遍历二叉树。函数的参数包括当前节点root
,以及需要找到的两个节点p
和q
。 -
在递归函数中,先进行递归遍历左子树和右子树,分别得到左右子树是否找到了节点
p
和q
的标志。 -
如果左右子树都找到了
p
和q
节点,或者左右子树中找到了p
或q
节点,并且当前节点的值等于p
或q
节点的值,那么当前节点就是最近公共祖先节点。 -
在这种情况下,将
ans
指向当前节点,更新最近公共祖先节点。 -
最后,返回当前子树是否找到了
p
或q
节点的结果。 -
在
lowestCommonAncestor
函数中,从根节点开始调用dfs
函数进行遍历,并返回最近公共祖先节点的指针。
解法二:哈希表
/**
* 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:
unordered_map<int, TreeNode*> fa;
unordered_map<int, bool> vis;
void dfs(TreeNode* root) {
if (root->left) {
fa[root->left->val] = root;
dfs(root->left);
}
if (root->right) {
fa[root->right->val] = root;
dfs(root->right);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
fa[root->val] = NULL;
dfs(root);
while (p) {
vis[p->val] = true;
p = fa[p->val];
}
while (q) {
if (vis[q->val])
return q;
q = fa[q->val];
}
return NULL;
}
};
-
首先定义了两个
unordered_map
,fa
用来记录每个节点的父节点,vis
用来记录节点是否被访问过。 -
定义了一个递归函数
dfs
,用来构建节点和父节点的映射关系。 -
在递归函数中,先判断当前节点是否有左子树和右子树,如果有则分别记录它们的父节点,并递归调用
dfs
函数。 -
在
lowestCommonAncestor
函数中,首先将根节点的父节点设为NULL
,然后调用dfs
函数构建节点和父节点的映射关系。 -
接下来,从节点
p
开始,一直向上遍历到根节点,每次将节点p
标记为已经访问过。 -
然后从节点
q
开始,一直向上遍历到根节点,每次判断节点q
是否已经被访问过,如果是,则说明节点q
是最近公共祖先节点,返回它。 -
如果没有找到最近公共祖先节点,则返回
NULL
。