1151 LCA in a Binary Tree (30 分)

问题描述:给定一颗二叉树的中序和先序遍历,求两个结点的最低公共祖先(LCA)

解题思路:首先中序和先序建树(数组或链表),注意只需记录结点的父亲即可,计算每个结点的高度,首先将两点回溯到同一高度,再 继续回溯直到相等。

AC代码:

/*
**1151 LCA in a Binary Tree (30 分)-------------30
**给一颗二叉树的中序和先序,找两个结点的最近公共祖先,
**$$两结点u,v的最近祖先结点可能有三种情况:1.u在v的子树中或者相反,2两者在公共祖先结点不同子树中,3两者是一个点。
**这是题目所提示的;所以应该以两者的层数和结点的值来判断。
**#1根据先序和中序确定每个结点的父亲结点及层数;#2将低的层次的点回溯到对应高层次的祖先结点,再依据值进行判断或回溯。
**建树有两种,指针或数组,注意需要根据值查找结点,所以需要散列便于快速查找值的位置。
*/
#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
#define MAX 10005
int pre[MAX],in[MAX];
typedef struct node{
    int lev,par;
}node;
map<int,node>arr;//int 的高度和父亲
void CreatTree(int inL,int inR,int preL,node no)//中序先序建后序
{
    if(inL>inR)return;
    int i=inL;
    while(in[i]!=pre[preL])++i;//中序中根节点位置
    arr[pre[preL]]=no;
    ++no.lev;no.par=pre[preL];
    CreatTree(inL,i-1,preL+1,no);
    CreatTree(i+1,inR,preL+i-inL+1,no);//先序中右子树根节点为  当前根节点位置+左子树个数+1
}
int main()
{
    freopen("test.txt","r",stdin);
    int i,N,M;
    scanf("%d %d",&M,&N);
    for(i=0;i<N;++i)scanf("%d",&in[i]);
    for(i=0;i<N;++i)scanf("%d",&pre[i]);
    node no;no.lev=0;no.par=-1;
    CreatTree(0,N-1,0,no);
    while(M--){
        int a,b;
        scanf("%d %d",&a,&b);
        if(!arr.count(a)&&!arr.count(b))printf("ERROR: %d and %d are not found.\n",a,b);//没有a,b结点
        else if(!arr.count(a)||!arr.count(b))printf("ERROR: %d is not found.\n",arr.count(a)?b:a);//没有其中一个结点
        else if(a==b)printf("%d is an ancestor of %d.\n",a,b);//同一结点
        else{
            int x=a,y=b;
            while(arr[a].lev<arr[b].lev)b=arr[b].par;//b回溯到与a同一层,
            if(b==a){printf("%d is an ancestor of %d.\n",a,y);continue;}//a是b祖先
            while(arr[b].lev<arr[a].lev)a=arr[a].par;//a回溯到与b同一层
            if(b==a){printf("%d is an ancestor of %d.\n",b,x);continue;}//b是a祖先
            while(b!=a){a=arr[a].par;b=arr[b].par;}//一起回溯。
            printf("LCA of %d and %d is %d.\n",x,y,a);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值