PAT.1143 Lowest Common Ancestor

这篇博客讨论了一种在给定BST的前序遍历情况下,寻找两个节点最低公共祖先(LCA)的方法。通过前序中序构建BST,然后从根节点开始同时搜索两个节点,找到分叉点即为LCA。代码实现中存在一个测试点2的错误,即当查询的两个节点相同时,输出应当表明其中一个节点是另一个的祖先。修正这个问题后,代码可以正确找到LCA。
摘要由CSDN通过智能技术生成

PAT.1143 Lowest Common Ancestor

题目链接

给定一棵BST的前序遍历,根据若干查询给出两节点的最低公共祖先(Lowest Common Ancestor)。

还是一贯的套路,根据前序中序建树,然后从根开始同时搜索两个节点,找到分叉点即可。

一些尝试

按照上面的思路,建树->判断->搜索,最终测试点2答案错误,关于测试点2的问题下面会讲。

以下代码得分29/30

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;

struct node{
    int val;
    node *left,*right;
    node(){}
    node(int t){
        this->val = t;
        this->left = this->right = nullptr;
    }
};

int queryCnt,nodeCnt,preOrder[10005],inOrder[10005],tNode1,tNode2;
map<int,int> mark;
node *root;

node *build(int pl,int pr,int il,int ir){
    int rootVal = preOrder[pl],rootInOrderIndex = il;
    node *cNode = new node(rootVal);
    if(pl > pr || il > ir) return nullptr;
    else if(pl == pr || il == ir) return cNode;
    
    while(inOrder[rootInOrderIndex] != rootVal) rootInOrderIndex++;
    int leftChildSize = rootInOrderIndex - il;
    cNode->left = build(pl + 1,pl + leftChildSize,il,rootInOrderIndex - 1);
    cNode->right = build(pl + leftChildSize + 1,pr,rootInOrderIndex + 1,ir);
    
    return cNode;
}

int findLCA(int a,int b){
    int biggerNode = max(a,b),smallerNode = min(a,b);
    node *ptr = root,*lcaPtr = nullptr;
    bool isBiggerAnc = false,isSmallerAnc = false;
    while(ptr != nullptr){
        lcaPtr = ptr;
        if(biggerNode == ptr->val && smallerNode < ptr->val){
            //the bigger one is an ancestor of the smaller one
            isBiggerAnc = true;
            break;
        }else if(smallerNode == ptr->val && biggerNode > ptr->val){
            //the smaller one is an ancestor of the bigger one
            isSmallerAnc = true;
            break;
        }else{
            //LCA,落在两边的情况直接得到LCA,指向一边的情况继续搜索
            if(biggerNode < ptr->val){
                //向左
                ptr = ptr->left;
            }else if(smallerNode > ptr->val){
                //向右
                ptr = ptr->right;
            }else{
                //两边
                break;
            }
        }
    }
    if(isBiggerAnc) printf("%d is an ancestor of %d.\n",biggerNode,smallerNode);
    else if(isSmallerAnc) printf("%d is an ancestor of %d.\n",smallerNode,biggerNode);
    else printf("LCA of %d and %d is %d.\n",a,b,ptr->val);
}

//LCA肯定是两节点在搜索路径上的最低公共节点,从头到尾贪心找到最后一个连续的公共节点即可
int main(){
    cin>>queryCnt>>nodeCnt;
    for(int i = 0 ; i < nodeCnt ; ++i){
        cin>>preOrder[i];
        inOrder[i] = preOrder[i];
        mark[inOrder[i]]++;
    }
    sort(inOrder,inOrder + nodeCnt);
    root = build(0,nodeCnt - 1,0,nodeCnt - 1);
    while(queryCnt--){
        cin>>tNode1>>tNode2;
        if(mark[tNode1] == 0 && mark[tNode2] == 0) printf("ERROR: %d and %d are not found.\n",tNode1,tNode2);
        else if(mark[tNode1] == 0) printf("ERROR: %d is not found.\n",tNode1);
        else if(mark[tNode2] == 0) printf("ERROR: %d is not found.\n",tNode2);
        else findLCA(tNode1,tNode2);
    }
}

题解

测试点2其实就是查询的两个节点相同,而且都在树中的情况。

根据题干里说的,如果LCA是两个节点之一,就要输出a is an ancestor of b.这句话,而不是按照LCA的输出。那显然测试点2的情况下LCA的确是两个节点之一。

因此把:

	if(mark[tNode1] == 0 && mark[tNode2] == 0) printf("ERROR: %d and %d are not found.\n",tNode1,tNode2);
	else if(mark[tNode1] == 0) printf("ERROR: %d is not found.\n",tNode1);
	else if(mark[tNode2] == 0) printf("ERROR: %d is not found.\n",tNode2);
	else findLCA(tNode1,tNode2);

改成:

	if(mark[tNode1] == 0 && mark[tNode2] == 0) printf("ERROR: %d and %d are not found.\n",tNode1,tNode2);
	else if(mark[tNode1] == 0) printf("ERROR: %d is not found.\n",tNode1);
	else if(mark[tNode2] == 0) printf("ERROR: %d is not found.\n",tNode2);
	else if(tNode1 == tNode2) printf("%d is an ancestor of %d.\n",tNode1,tNode2);
	else findLCA(tNode1,tNode2);

特判一下就完事儿了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值