A1151
个人思路
题意
给出中序前序,找出一对测试节点的最深公共根节点
思路
与1143 Lowest Common Ancestor类似,但思考起来要比1143难,本题给出的是中序和前序而不是二叉搜索树,所以比较起来有些麻烦
起初思考利用中序构造二叉树,但是如何得到公共根节点?一开始的想法是公共根节点一定在两个测试节点之间(中序序列中),枚举两个节点之间的点,判断该节点是不是公共根节点,此时发现需要回溯
然后转变思路,类比1143,是着将二叉树转换为同结构的二叉搜索树,以满足比较大小即可找到公共根节点,发现难上加难
个人错误思路代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int M, N;
int in[maxn], pre[maxn];
unordered_map<int, int> mp;//记录数据和下标的映射
unordered_map<int, int> inpos;//中序中数据的位置
struct Node{
int data;
int left, right;
int level;
Node(){}
Node(int d, int l, int r)
{
data = d;
left = l;
right = r;
}
}nodes[maxn];
int pos = 1;
int newNode(int x)
{
nodes[pos] = Node(x, -1, -1);
mp[x] = pos;
return pos++;
}
int recreate(int preL, int preR, int inL, int inR)
{
if(preL > preR)
return -1;
int root = newNode(pre[preL]);
int k;
for(k = 0; k < inR; ++k)
{
if(in[k] == pre[preL])
{
break;
}
}
int numleft = k - inL;
nodes[root].left = recreate(preL + 1, preL + numleft, inL, k - 1);
nodes[root].right = recreate(preL + 1 + numleft, preR, k + 1, inR);
return root;
}
void levelOrder(int root)
{
queue<int> q;
q.push(root);
nodes[root].level = 1;
while(!q.empty())
{
int now = q.front();
q.pop();
int ll = nodes[now].left;
int rr = nodes[now].right;
//cout << nodes[now].data << " ";
if(ll != -1)
{
nodes[ll].level = nodes[now].level + 1;
q.push(ll);
}
if(rr != -1)
{
nodes[rr].level = nodes[now].level + 1;
q.push(rr);
}
}
}
int main(int argc, char *argv[]) {
scanf("%d%d", &M, &N);
for(int i = 0; i < N; ++i)
{
scanf("%d", &in[i]);
inpos[in[i]] = i;
}
for(int i = 0; i < N; ++i)
{
scanf("%d", &pre[i]);
}
int root = recreate(0, N - 1, 0, N - 1);
levelOrder(root);
//cout << endl;
while(M--)
{
int u, v;
scanf("%d%d", &u, &v);
int posu = mp[u], posv = mp[v];
//cout << posu << "****" << posv << endl;
if(posu == 0 && posv != 0)
printf("ERROR: %d is not found.\n", u);
else if(posu != 0 && posv == 0)
printf("ERROR: %d is not found.\n", v);
else if(posu == 0 && posv == 0)
printf("ERROR: %d and %d are not found.\n", u, v);
else
{
int inu = inpos[u], inv = inpos[v];
for(int i = inu; i <= inv; ++i)
{
}
}
}
return 0;
}
本题思路
首先!!!不用建树!!!
- 用map记录中序序列中每个数据的下标,所有下标指的都是中序序列的下标
- 发现公共节点一定在两个测试点的中间(中序序列中)
- 枚举遍历前序序列,若当前节点在二者之间,说明是公共节点
- 若当前节点等于二者下标的其中之一,说明当前节点是另一个节点的根节点
AC代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int M, N;
int in[maxn], pre[maxn];
unordered_map<int, int> inpos;//中序中数据的位置
int main(int argc, char *argv[]) {
scanf("%d%d", &M, &N);
for(int i = 1; i <= N; ++i)//下标从1开始
{
scanf("%d", &in[i]);
inpos[in[i]] = i;
}
for(int i = 1; i <= N; ++i)
{
scanf("%d", &pre[i]);
}
while(M--)
{
int u, v;
scanf("%d%d", &u, &v);
int inu = inpos[u], inv = inpos[v];
if(inu == 0 && inv != 0)//等于0说明该数据不在树中
printf("ERROR: %d is not found.\n", u);
else if(inu != 0 && inv == 0)
printf("ERROR: %d is not found.\n", v);
else if(inu == 0 && inv == 0)
printf("ERROR: %d and %d are not found.\n", u, v);
else
{
for(int i = 1; i <= N; ++i)//遍历先序序列
{
int now = pre[i];//当前节点的数值
int innow = inpos[now];//当前节点在中序中的下标
if((innow > inu && innow < inv) || (innow > inv && innow < inu))//下标在u,v之间
{
printf("LCA of %d and %d is %d.\n", u, v, now);
break;
}
else if(innow == inu)//与u相等即可,没有innow != inv的条件
{
printf("%d is an ancestor of %d.\n", u, v);
break;
}
else if(innow == inv)
{
printf("%d is an ancestor of %d.\n", v, u);
break;
}
else
continue;
}
}
}
return 0;
}