PAT 1151 LCA in a Binary Tree

这一题给出两个节点,找出在二叉树上的最近的公共祖先。
开头一想可以先建树然后保存路径找结果的方法,后来觉得这样代码量会很大,而且短时间写不出来,可能存在时间超限的风险。
改为类似于并查集的思维,用元素的下标指向父节点的下标,用的是先序数组的下标,先用先序遍历和中序遍历按照建树的思维对将元素的下标指向父节点的下标,完成一棵"反向树"。先用map来判断元素是否在树中,然后用两个节点的下标去查找结果,先用一个,将路径结果保存到map中,再用另一个遍历,查询在map中是否存在,若存在返回结果。(先用数组下标小的,因为是先序下标小的靠根节点更近,路径更短,不然会超时)。
看了一下别人,是直接根据中序和先序不需要建树,直接遍历得出结果。按先序遍历的顺序,根据当前根节点,x和y的节点的中序遍历下标进行判断,若x,y的下标<当前根节点的下标,则在左子树上寻找,若x,y的下标>当前根节点的下标,则在右子树上寻找,若当前根节点在x,y之间,则当前根节点即为所求。
有人根据这种思想得出,LCA一定在中序遍历x和y之间的序列上(包括x,y),而且下标在先序遍历数组中是最小的。直接遍历先序数组,找到第一个中序数组下标在x,y的下标之间(包括x,y)的元素即为结果。(直接看出了本质)。(别人的思想:https://blog.csdn.net/liuchuo/article/details/82560863)
(用时:1:38:13.59)

#include <bits/stdc++.h>
using namespace std;
const int INF = 10000000;
const int LEN = 10000;
map<int, int> valueMap;
vector<int> inorder;
vector<int> preorder;
int t=-1;
void buildTree(int leftIndex,int rightIndex,int father[],int fatIndex)
{
    if(leftIndex>=rightIndex) {
        return;
    }
    int index = rightIndex;
    t++;
    father[t]= fatIndex;
    int currentIndex =t;
    for(int i=leftIndex; i<rightIndex; i++) {
        if(preorder[t] == inorder[i] ) {
            index = i;
            break;
        }
    }
    if(rightIndex-leftIndex>1) {
        buildTree(leftIndex,index,father,currentIndex);
        buildTree(index+1,rightIndex,father,currentIndex);
    }


}

int GetLCA(int xIndex,int yIndex,int father[])
{
    map<int,int> xAncestor;
    int lca = xIndex;
    int t = xIndex < yIndex?xIndex:yIndex;

    while(father[t]!=t) {
        xAncestor[t] = 1;
        t = father[t];
    }
    xAncestor[t] = 1;

    t = xIndex < yIndex?yIndex:xIndex;
    bool findLCA = false;
    while(father[t]!=t) {
        if(xAncestor.count(t)) {
            break;
        }
        t=father[t];
    }
    lca = t;
    return t;
}
int main()
{
    int n,m;
    scanf("%d%d",&m,&n);
    int x;
    int father[n];
    for(int i=0; i<n; i++) {
        scanf("%d",&x);
        inorder.push_back(x);
        valueMap[x]=1;
    }

    for(int i=0; i<n; i++) {
        scanf("%d",&x);
        preorder.push_back(x);
    }

    buildTree(0,n,father,0);

    int  y;
    for(int i=0; i<m; i++) {
        scanf("%d%d",&x,&y);
        bool hasX = false;
        bool hasY = false;
        if(valueMap.count(x)) {
            hasX = true;
        }

        if(valueMap.count(y)) {
            hasY = true;
        }

        if(hasX&&hasY) {
            int xIndex = 0;
            int yIndex = 0;
            for(int i=0; i<n; i++) {
                if(preorder[i]==x) {
                    xIndex = i;
                }
                if(preorder[i]==y) {
                    yIndex = i;
                }
            }
            int lca = GetLCA(xIndex,yIndex,father);
            if(lca == xIndex) {
                printf("%d is an ancestor of %d.\n",preorder[lca],preorder[yIndex]);
            } else if(lca ==yIndex) {
                printf("%d is an ancestor of %d.\n",preorder[lca],preorder[xIndex]);
            } else {
                printf("LCA of %d and %d is %d.\n",preorder[xIndex],preorder[yIndex],preorder[lca]);
            }

        } else if(hasX&&!hasY) {
            printf("ERROR: %d is not found.\n",y);
        } else if(!hasX&&hasY) {
            printf("ERROR: %d is not found.\n",x);
        } else {
            printf("ERROR: %d and %d are not found.\n",x,y);
        }
    }




    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值