PAT 1143. Lowest Common Ancestor (30分)
分析
给一个二叉搜索树的前序遍历数组,让求最近公共祖先。
首先最容易想到的办法就是:重建树,然后找U和V的祖先,分别得到U和V的祖先数组。同时从后到前遍历U和V的祖先数组,设为ancU, ancV,最后一个满足ancU==ancV的就是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)
{
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",&pre[i]);
in[i] = pre[i];
}
sort(in,in+N);
for(int i=0;i<N;i++)
{
node[i].val = in[i];
pos[node[i].val] = i;
}
rebuild(0,N-1,0,N-1,-1);
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;
}
再次分析
解法1还是比较麻烦的,代码也比较长。看了柳婼的博客才知道根本没有必要重建树。
1、因为是二叉搜索树,所以最近公共祖先的节点值一定在U和V之间。
2、因为前序遍历是按该节点、左子树、右子树顺序遍历的:
所以从前往后遍历前序数组pre,设节点为ans,第一个满足(ans>=U&&ans<=V)||(ans>=V&&ans<=U)的ans就是U和V的最近公共祖先。
解法2
#include <iostream>
#include <vector>
#include <cstdio>
#include <map>
#define MAX 10100
using namespace std;
map<int, bool> mp;
int M,N;
int pre[MAX];
int main()
{
scanf("%d%d",&M,&N);
for(int i=0;i<N;i++)
{
scanf("%d",&pre[i]);
mp[pre[i]] = true;
}
for(int i=0;i<M;i++)
{
int U,V,ans;
scanf("%d%d",&U,&V);
for(int j=0;j<N;j++)
{
ans = pre[j];
if((ans>=U&&ans<=V)||(ans>=V&&ans<=U))
break;
}
if(!mp[U])
{
if(!mp[V])
printf("ERROR: %d and %d are not found.\n",U,V);
else printf("ERROR: %d is not found.\n",U);
}
else if(!mp[V])
printf("ERROR: %d is not found.\n",V);
else if(ans==U)
printf("%d is an ancestor of %d.\n", ans, V);
else if(ans==V)
printf("%d is an ancestor of %d.\n",ans,U);
else
printf("LCA of %d and %d is %d.\n",U,V,ans);
}
}