一、236 二叉树的最近公共祖先
给定一个二叉树,找到该树两个指定节点的最近公共祖先。
1.递归实现
利用深度优先遍历的思想,递归压栈实现从二叉树的叶子结点逐层向上判断,递归函数中应该对满足题目条件的二叉树节点进行记录,该节点即为要查找的最近公共祖先。重点在于命中条件的分析,满足要求的祖先节点应该满足下述要求中的一条:
- 该节点的左子树和右子树分别包含p节点和q节点,当前节点就是最近公共祖先;
- 该节点本身为p节点或q节点,其左子树或右子树包含另一个给定节点。
用lson表示当前节点的左子树是否包含给定节点,用rson表示当前节点右子树是否包含给定节点。
代码实现:
class Solution {
public:
//深度优先遍历函数,用来完善fa哈希表,找到所有节点和其父节点的映射关系
bool dfs(TreeNode* node, TreeNode* p, TreeNode* q){
// 递归终止条件
if(node == nullptr) return;
bool lson = dfs(node->left, p, q);
bool rson = dfs(node->right, p, q);
// 判断命中条件
if((lson && rson) || (node->val == p->val || node->val == q->val) && (lson || rson)){
ans = node;
}
return lson || rson || node->val == p->val || node->val == q->val;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
private:
TreeNode* ans; //用于记录递归中命中的节点
};
2.哈希表实现
采用哈希表fa记录二叉树中所有节点与其父节点(树的根节点的父节点记为nullptr)的映射关系。然后两个给定节点向上搜索,二者重合的第一个节点即为最近公共祖先。总结:共需要准备两张哈希表
- 哈希表fa用于记录树中所有节点和其父节点的映射关系,即unordered_map<TreeNode*, TreeNode*>
- 哈希表vis用于记录从一个给定节点(假设从p出发)向上遍历的所有祖先节点,当从另一个给定节点出发向上搜索的过程中命中的第一个节点即为公公祖先
代码实现:
class Solution {
public:
//深度优先遍历函数,用来完善fa哈希表,找到所有节点和其父节点的映射关系
void dfs(TreeNode* node){
if(node -> left){
fa[node -> left] = node;
dfs(node -> left);
}
if(node -> right){
fa[node -> right] = node;
dfs(node -> right);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
fa[root] = nullptr;
dfs(root);
while(p != nullptr){ //从节点p向上遍历并记录
vis[p] = true;
p = fa[p];
}
while(q != nullptr){ //从节点q向上遍历并判断
if(vis[q]){
return q;
}
q = fa[q];
}
return nullptr;
}
private:
unordered_map<TreeNode*, TreeNode*> fa;
unordered_map<TreeNode*, bool> vis;
};
二、235 二叉搜索树的最近公共祖先
上述两种针对一般二叉树的解法对二叉搜索树也一定适用,只是没有利用到二叉搜索树的特性,下述介绍针对二叉搜索树特性的实现方法。
1.利用数值分岔点
满足给定节点的最近公共祖先节点,其节点值一定在给出两个节点之间,可以用节点值在遍历过程中作为判断条件对搜索方向进行划分,遍历从根节点开始,每次遍历到一个新节点的判断条件如下:
- 当给定节点值均小于当前遍历节点的值,则向当前节点的左子树移动;
- 当给定节点值均大于当前遍历节点的值,则向当前节点的右子树移动;
- 除此之外,当前节点都是满足条件的分岔点。
注意:3中实际包括了当前遍历节点是给定节点的情况。
实现代码:
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode* ancestor = root;
while(true){
if(p->val < ancestor->val && q->val < ancestor->val){
ancestor = ancestor->left;
}
else if(p->val > ancestor->val && q->val > ancestor->val){
ancestor = ancestor -> right;
}
else{
break;
}
}
return ancestor;
}
};