给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
_______3______
/ \
___5__ ___1__
/ \ / \
6 _2 0 8
/ \
7 4
示例 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。因为根据定义最近公共祖先节点可以为节点本身。
说明:
- 所有节点的值都是唯一的。
- p、q 为不同节点且均存在于给定的二叉树中。
-
思路分析:
通过对题目的分析,我们发现,如果两个节点是一个在左,一个在右,最近祖先就是root,如果不是一左一右,依旧是递归子问题,两个都是左,就去左子树里面找,两个都在右,就去右子树里面去找。
-
具体代码如下:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
bool FindNode(struct TreeNode* root,struct TreeNode* node)
{
if(root==NULL)
{
return false;
}
if(root==node)
{
return true;
}
return FindNode(root->left,node)
|| FindNode(root->right,node);
}
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
if(root==NULL)
{
return NULL;
}
if(root==p||root==q)
{
return root;
}
bool pInLeft,pInRight,qInLeft,qInRight;
if(FindNode(root->left,p))
{
pInLeft= true;
pInRight= false;
}
else
{
pInRight=true;
pInLeft= false;
}
if(FindNode(root->left,q))
{
qInLeft= true;
qInRight= false;
}
else
{
qInRight=true;
qInLeft= false;
}
if(pInLeft&&qInLeft)
{
return lowestCommonAncestor( root->left,p,q);
}
else if(pInRight&&qInRight)
{
return lowestCommonAncestor( root->right,p,q);
}
else
{
return root;
}
}
上面代码使用递归时,时间复杂度为O(N^2),下面代码利用栈,把时间复杂度优化到O(N),具体代码如下:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
typedef struct TreeNode* STDataType;
typedef struct Stack
{
STDataType* _a;
int _top;//栈顶
int _capacity;
}Stack;
void StackInit(Stack* ps, int n)
{
assert(ps);
ps->_a = (STDataType*)malloc(sizeof(STDataType)*n);
ps->_top = 0;
ps->_capacity = n;
}
void StackDestroy(Stack* ps)
{
assert(ps);
free(ps->_a);
ps->_a = NULL;
ps->_top = ps->_capacity = 0;
}
void StackPush(Stack* ps, STDataType x)//在栈顶入数据
{
assert(ps);
if (ps->_top == ps->_capacity)//容量检测
{
ps->_a = (STDataType*)realloc(ps->_a, ps->_capacity * 2 * sizeof(STDataType));
ps->_capacity *= 2;
}
ps->_a[ps->_top] = x;
ps->_top++;
}
void StackPop(Stack* ps)//在栈顶出数据
{
assert(ps);
if (ps->_top > 0)
{
ps->_top--;
}
}
STDataType StackTop(Stack* ps)//取出栈顶的数据
{
assert(ps);
return ps->_a[ps->_top - 1];
}
int StackSize(Stack* ps)//返回数据个数
{
assert(ps);
return ps->_top;//top其实就是链表中的size
}
int StackEmpty(Stack* ps)
{
assert(ps);
if (ps->_top == 0)
{
return 0;
}
else
{
return 1;
}
}
void Find(Stack* st, struct TreeNode* root, struct TreeNode* p)
{
if(root == NULL)
return ;
struct TreeNode* cur = root;
struct TreeNode* prev;
while(cur != NULL || StackEmpty(st) != 0)
{
while(cur)//遍历左路节点
{
if(cur->val == p->val)//若是p就是cur,把cur入栈后,直接返回
{
StackPush(st,cur);
return;
}
else//遍历左路节点,找p的路径
{
StackPush(st, cur);
cur = cur->left;
}
}
//访问右路节点
struct TreeNode* top = StackTop(st);
if(top->right == NULL|| top->right==prev)
{
prev=top;
StackPop(st);
cur= NULL;
}
else
cur = top->right;
}
}
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q)
{
Stack st_p;
Stack st_q;
StackInit(&st_p,10);
StackInit(&st_q,10);
if(root==NULL)
return NULL;
//找p的路径
Find(&st_p, root, p);
//找q的那条路径
Find(&st_q, root, q);
int sz1=StackSize(&st_p);
int sz2=StackSize(&st_q);
int gap=abs(sz1-sz2);
if(sz1<sz2)
{
while(gap--)
{
StackPop(&st_q);
}
}
else
{
while(gap--)
{
StackPop(&st_p);
}
}
//同时pop
if(sz1 ==0)
return root;
struct TreeNode* top;
while(StackEmpty(&st_p)!=0&&StackEmpty(&st_q)!=0)
{
struct TreeNode* top1=StackTop(&st_p);
struct TreeNode* top2=StackTop(&st_q);
if(top1->val!=top2->val)
{
StackPop(&st_p);
StackPop(&st_q);
}
else
{
top = top1;
break;
}
}
return top;
}