您的位置:首页 > 职场人生

《剑指offer》面试题50 树中两个结点的最低公共祖先

2014-04-05 14:12 477 查看
原题请见 http://ac.jobdu.com/problem.php?pid=1509

题目描述:

给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。

分析:

1.首先分析这个树的形态,是不是二叉树,如果是会怎样求解,如果不是的话我们又该如何求解(或者说如何将一棵树转成二叉树)

2.如果这棵树是二叉树的话,那么如何得到这棵树,一般给的是先根遍历,那我们需要根据先根遍历构造出这棵树出来(中根的话怎样,后根遍历的话又怎样)

3.上面说的只是准备工作,现在才是这个问题的解决关键。公共祖先必然存在于根节点到它的路径上,因此我们再求得从根节点到它的路径。

4.分别得到两个节点的路径后,剩下的就是求公共节点了,这个非常容易,我们只需从后向前比较即可。

下面是完整描述:

题目描述:

给定一棵树,同时给出树中的两个结点,求它们的最低公共祖先。

输入:

输入可能包含多个测试样例。

对于每个测试案例,输入的第一行为一个数n(0<n<1000),代表测试样例的个数。

其中每个测试样例包括两行,第一行为一个二叉树的先序遍历序列,其中左右子树若为空则用0代替,其中二叉树的结点个数node_num<10000。

第二行为树中的两个结点的值m1与m2(0<m1,m2<10000)。

输出:

对应每个测试案例,

输出给定的树中两个结点的最低公共祖先结点的值,若两个给定结点无最低公共祖先,则输出“My God”。

样例输入:
2
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0
6 8
1 2 4 6 0 0 7 0 0 5 8 0 0 9 0 0 3 0 0
6 12

样例输出:
2
My God


代码如下:

#include <iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>

typedef  struct node       //定义树的结构
{
int data;
struct node *left;
struct node *right;
}BNode,*BinNode;

int path_a[10010];    //保存根节点到给定节点的路径,数组开这么大是防止树退化成一个线性表
int path_b[10010];
int node[10010];
static int flag;     //在递归计算根节点到给定节点的路径时,标记是否查找成功,成功为1,否则为0
static int len;
static int k=0;      //统计树中有多少个非叶节点,用于判定给定节点是否在树中,不在树中的话直接输出"My God"
static int length;   //用于标记路径中的最后一个节点的位置,即所给定节点在树中的层数,层数从0开始计数

void BuildTree(BNode *&root)
{
int x;
scanf("%d",&x);
if(0==x)
{
root=NULL;
}
else
{
root=(BNode *)malloc(sizeof(BNode));
root->data=x;
node[k++]=x;
BuildTree(root->left);
BuildTree(root->right);
}
}
void  find_path(BNode *root,int path[],int current,int key,int *flag)
{
if (*flag==0)
{
if(root!=NULL && root->data==key)
{
path[current]=key;
length=current;
*flag=1;
return  ;
}
else
{
for(int i=0;i<2;i++)
{
if(*flag==0 && i==0 && root!=NULL)            //递归搜索左子树
{
path[current]=root->data;
find_path(root->left,path,current+1,key,flag);

}
if (*flag==0 && i==1&&root!=NULL)          //递归搜索右子树
{
path[current]=root->data;
find_path(root->right,path,current+1,key,flag);
}
}
}
}
}

int find_common_father(int *a,int *b,int len1,int len2)      //从后向前搜索公共祖先,这样保证是最低的
{
int compositon=len1;
if(compositon>len2)
{
compositon=len2;
}
while (a[compositon]!=*(b+compositon))
{
compositon--;
}
return compositon
;
}

void Print_Tree(BNode *root)
{
if (root!=NULL)
{
//printf("%d ",root->data);
Print_Tree(root->left);
printf("%d ",root->data);
Print_Tree(root->right);
}
}

int main()

{
int n;
scanf("%d",&n);
while(n--)
{
int node_a,node_b;
memset(path_a,0,sizeof(path_a));
memset(path_b,0,sizeof(path_b));
k=0;
BNode *root;
BuildTree(root);
scanf("%d %d",&node_a,&node_b);
int answer1=0;
int answer2=0;
for(int i=0;i<k;i++)         //用于判断给定节点node_a和node_b是否在树中
{
if(node_a==node[i])
{
answer1=1;
}
if(node_b==node[i])
{
answer2=1;
}
}
if(answer1&&answer2)   //如果给定节点都在树中的话我们才需要计算路径和最低公共祖先
{
int len1,len2;
flag=0;
len=0;
find_path(root,path_a,len,node_a,&flag);
len1=length;

len=0;
flag=0;
find_path(root, path_b, len, node_b, &flag);
len2=length;

int father=find_common_father(path_a, path_b, len1, len2);
printf("%d\n",path_a[father]);
}
else
{
printf("My God\n");
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息