PAT 1151 LCA in a Binary Tree (30分) (两种解法)
分析
这个和PAT 1143是类似的题目,区别就是PAT 1143是二叉搜索树,而这一题就是个普通的二叉树。
第一种解法必然是无脑的重建树,然后找U和V的祖先。
解法1
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#define MAX 10100
using namespace std;
int N,M;
int pre[MAX];
int in[MAX];
map<int,int> pos;
vector<int> ancestor[MAX];
int father[MAX];
struct Node
{
int val;
int father = -1;
}node[MAX];
void rebuild(int iL,int iR,int pL,int pR,int rindex)
{
//cout<<iL<<" "<<iR<<" "<<pL<<" "<<pR<<endl;
if(iL>iR||pL>pR)
return;
int root = pre[pL];
int m = pos[root];
node[m].father = rindex;
rebuild(iL,m-1,pL+1,pL+m-iL,m);
rebuild(m+1,iR,pL+m-iL+1,pR,m);
}
int main()
{
scanf("%d%d",&M,&N);
for(int i=0;i<N;i++)
{
scanf("%d",&in[i]);
node[i].val = in[i];
pos[node[i].val] = i;
}
for(int i=0;i<N;i++)
scanf("%d",&pre[i]);
rebuild(0,N-1,0,N-1,N);
for(int i=0;i<M;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(pos.find(a)==pos.end())
{
if(pos.find(b)==pos.end())
{
printf("ERROR: %d and %d are not found.\n",a,b);
}
else{
printf("ERROR: %d is not found.\n",a);
}
}
else if(pos.find(b)==pos.end())
{
printf("ERROR: %d is not found.\n",b);
}
else{
if(a==b)
{
printf("%d is an ancestor of %d.\n",a,b);
continue;
}
int aindex = pos[a];
int bindex = pos[b];
int ra = aindex;
int rb = bindex;
vector<int> afa, bfa;
bool flag = true;
while(ra!=-1)
{
afa.push_back(ra);
if(node[ra].father == bindex)
{
flag = false;
printf("%d is an ancestor of %d.\n",b, a);
break;
}
ra = node[ra].father;
}
while(flag&&rb!=-1)
{
bfa.push_back(rb);
if(node[rb].father == aindex)
{
printf("%d is an ancestor of %d.\n",a, b);
flag = false;
break;
}
rb = node[rb].father;
}
if(flag)
{
int ai = afa.size()-1;
int bj = bfa.size()-1;
while(ai>=0&&bj>=0&&afa[ai]==bfa[bj])
{
ai--;
bj--;
}
printf("LCA of %d and %d is %d.\n",a, b, in[afa[ai+1]]);
}
}
}
return 0;
}
再次分析
这题本质上和PAT 1143没什么不同。普通的二叉搜索树用一个字典pos映射一下就可转换成二叉搜索树,然后就可以用老方法求解啦。PAT 1143题解
1、在中序遍历中,最近公共祖先的位置一定在U和V之间。
2、在前序遍历中,是按该节点、左子节点、右子节点的顺序遍历的:
所以,遍历前序遍历数组,设序号为i,第一个满足(pos[pre[i]]>=U&&pos[pre[i]]<=V)||(pos[pre[i]]>=V&&pos[pre[i]]<=U)
的pos[pre[i]]
就是最近公共祖先中序遍历的下标。
解法2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#define MAX 10100
using namespace std;
int M,N;
int pre[MAX];
int in[MAX];
map<int,int> pos;
int main()
{
scanf("%d%d",&M,&N);
for(int i=0;i<N;i++)
{
scanf("%d",&in[i]);
pos[in[i]] = i;
}
for(int i=0;i<N;i++)
scanf("%d",&pre[i]);
for(int i=0;i<M;i++)
{
int U,V;
scanf("%d%d",&U,&V);
if(pos.find(U)==pos.end())
{
if(pos.find(V)==pos.end())
{
printf("ERROR: %d and %d are not found.\n",U,V);
}
else printf("ERROR: %d is not found.\n",U);
}
else if(pos.find(V)==pos.end())
printf("ERROR: %d is not found.\n",V);
else{
int ans = 0;
int posU = pos[U];
int posV = pos[V];
for(int i=0;i<N;i++)
{
int p = pos[pre[i]];
if((p>=posU&&p<=posV)||(p>=posV&&p<=posU))
{
ans = p;
break;
}
}
ans = in[ans];
if(ans==U)
printf("%d is an ancestor of %d.\n",U,V);
else if(ans==V)
printf("%d is an ancestor of %d.\n",V,U);
else printf("LCA of %d and %d is %d.\n",U,V,ans);
}
}
return 0;
}