目录
题目:
示例:
分析:
代码:
题目:
示例:
分析:
给我们一棵二叉树,然后给我们pq两个节点,让我们找出二叉树中它们俩的最近的公共祖先。
那么什么样的节点是它们俩的最近的公共祖先呢,是有两种情况,第一种情况的pq两个节点都在同一条路径上,像下图这样:
那这时pq的最近公共祖先就是pq之中更靠进上层的那个节点,也就是pq之中有个节点是自己的祖先节点。
另一种情况就是,他们分布在它们公共祖先的左右两侧,也就是pq里其中一个在最近公共祖先的左子树上,另一个在最近公共祖先的右子树上,像下图这样:
因为pq已经各自分布在这个节点的左右两侧了,如果这个节点再往下走,不管是走哪个方向,都不可能再同时是它们两个节点的公共祖先了。
所以我们在递归遍历二叉树的时候,一旦发现了pq分布在某个节点的左右两侧,或是直接遍历到了pq节点,那就将当前节点返回出去即可。
我们做常规的遍历二叉树,并且再遍历里头再套一层递归遍历分别去当前节点的左子树和右子树寻找是否有pq节点。
在递归遍历之前先检测当前节点是否是pq之一,是的话直接返回当前节点。
如果pq分别分布在当前节点的左右子树,那么也直接返回当前节点。
最后一种情况就是,pq分布在当前节点的同一侧。
这时候虽然当前节点也还是两个节点的公共祖先,但并不是最近的公共祖先,并且因为pq都在当前节点的某棵子树上(左子树或是右子树),那么它们的最近公共祖先必然是在当前节点的子树,所以在我们需要将当前节点向那棵子树上转移,直到出现上面第一第二种情况。
代码:
class Solution {
public:
bool find(TreeNode* root,TreeNode*p,TreeNode* q){ //寻找是否有pq
if(root==nullptr) return false;
if(root==p || root==q) return true;
return find(root->left,p,q)||find(root->right,p,q);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root==p||root==q) return root;
TreeNode* res=root;
bool l=find(root->left,p,q);bool r=find(root->right,p,q);
while(l||r){
//如果自己本身就是其中一个节点,那么直接返回即可
if(res==p||res==q) return res;
if(l&&!r){ //如果pq全部集中在左子树,就往左子树移动
res=res->left;
}else if(r&&!l){ //如果pq全部集中在右子树,就往右子树移动
res=res->right;
}else{ //如果是左右各占一个,那么返回该节点
return res;
}
//寻找pq的分布情况
l=find(res->left,p,q);
r=find(res->right,p,q);
}
return root;
}
};