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);
特判一下就完事儿了。