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

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-21 09:12   31   0

原题请见 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");
        }
    }
    
}


分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP