题目
给定一棵二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义: “对于有根树T
的两个结点u
、v
,最近公共祖先表示一个结点x
,满足x
是u
、v
的祖先且x
的深度尽可能大。”(一个节点也可以是它自己的祖先)
例如,节点5
和节点1
的最近公共祖先是节点3
;节点5
和节点4
的最近公共祖先是节点5
,因为根据定义,一个节点可以是它自己的祖先。
题解
这道题应该是面试常考题。
方法一
可以考虑直接用两个数组分别记录u
和v
的路径,然后遍历两个路径找公共祖先。将寻找最近公共祖先转换为两个数组找公共节点。
/**
* 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:
bool getAncestor(TreeNode* root,TreeNode *p,vector<TreeNode*> &vec){
if(root==NULL) return false;
if(root==p){
vec.push_back(root);
return true;
}
if(getAncestor(root->left,p,vec)||getAncestor(root->right,p,vec)){
vec.push_back(root);
return true;
}
return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
vector<TreeNode*> vp,vq;
getAncestor(root,p,vp);
getAncestor(root,q,vq);
int n=vp.size(),m=vq.size();
while(n>0&&m>0&&vp[n-1]==vq[m-1]){
n--;
m--;
}
return vp[n];
}
};
方法二
如果不能使用辅助数组来记录路径。那么可以考虑同时在一棵二叉树中查找p
和q
两个节点,如果只找到了p
节点则返回1
,如果只找到了q
节点,则返回2
,如果同时找到p
和q
节点,则返回3
,其余情况返回0
,那么根据返回值就可以判断是否是公共祖先。具体代码如下:
/**
* 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:
int getRes(TreeNode *root,TreeNode *p,TreeNode* q,TreeNode *&res){
if(root==NULL||res!=NULL) return 0;
int l=getRes(root->left,p,q,res);
if(l==3) return 3; //左子树同时找到p和q
int r=getRes(root->right,p,q,res);
if(r==3) return 3; //右子树同时找到p和q
//左子树和右子树分别找到p和q,则当前节点为最近公共祖先
if((l==1&&r==2)||(l==2&&r==1)){
res=root;
return 3;
}
//当前节点为p,且左子树或者右子树找到q。或者当前节点为q,且左子树或者右子树找到p
if((root==p&&(l==2||r==2))||(root==q&&(l==1||r==1))){
res=root;
return 3;
}
if(root==p||(l==1||r==1)) return 1;
else if(root==q||(l==2||r==2)) return 2;
else return 0;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
TreeNode *res=NULL;
getRes(root,p,q,res);
return res;
}
};