1,题目
2,思路分析
-
一开始想着根据pre和in序列先构建一颗bt,然后使用dfs遍历到对应的结点时,存储下路径,这个路径上的点就是U的所有祖先,同理找出U和V的祖先后“由后往前”就可以找到最近的祖先结点。
-
结果:。。。尴尬了,最后两个点超时,想了下,结点范围10000,最坏情况下必然超时。
-
改进1:用空间换时间,实现把所有结点的路径存储下来,这样只需要一遍dfs就可以把所有的结点的祖先找出来,然后同样的方法找出最近的祖先即可,结果。。。又尴尬了,空间不够。。。
-
最后:苦思之前有一题的思路,结点U和V的祖先一定在pre序列的左边(注意包含U和V中前序序列考前的元素,因为可能U是V的祖先,或者反之),同时也一定在inorder序列的中间(同时包含U和V的中序序列,道理同前)。这样一来,不需要建树就可以找出最近祖先
-
步骤:
-
1,输入序列时同时用map分别记录各个元素在preorder和inorder中的位置,为之后判断元素在U、V的前或中间提供便捷。
for(int i=0; i<N; ++i) {
scanf("%d",&insequence[i]);
allNum.insert(insequence[i]);
in_value_pos[insequence[i]]=i;
}
for(int i=0; i<N; ++i) {
scanf("%d",&presequence[i]);
pre_value_pos[presequence[i]]=i;
}
-
注意,allNum时一个set,记录出现的所有元素。
-
2,当输入了U,V后,通过前边的记录,分别找到U,V的preorder中靠左(靠前)的元素(从左到右!!!很重要,后边说明!)从左到右遍历,只要该元素在U,V的inorder序列的中间,就说明其是最近祖先!
举例:
如图:
前序序列:2,3,7,10,6,4,12,13,1,8,11,14,9,5
中序序列:10,7,6,3,12,4,13,2,11,8,14,1,9,5 -
例子1:
U=14,V=5
可见从前序序列,应从前序序列元素2–14依次判断,只有1符合在中序序列中,1处于14和5之间。 -
例子2:U=1,V=5
同理可得,1为最近祖先
- 关键分析:
为什么这样找到的一定是最近祖先??
1,结点的祖先一定在前序序列的左方(包含自身)
2,两节点的祖先一定在中序序列之间(包含两结点)
**3,这是最重要的一点,中序序列中,结点U和V之间的结点只能包含其最近的一个祖先和其他非祖先结点。 **
由此,找到的一定是最近祖先。
3,关键点
- 最近祖先:中序序列之间的结点只包含最近的一个祖先
4,注意点
- 注意先判断结点U和V是否在树中,这也是set的作用。
5,代码
#include<stdio.h>
#include<set>
#include<algorithm>
#include<map>
using namespace std;
const int Maxn=10010;
int insequence[Maxn],presequence[Maxn];
map<int,int> in_value_pos,pre_value_pos;
int main() {
int M,N;
scanf("%d %d",&M,&N);
set<int> allNum;
for(int i=0; i<N; ++i) {
scanf("%d",&insequence[i]);
allNum.insert(insequence[i]);
in_value_pos[insequence[i]]=i;
}
for(int i=0; i<N; ++i) {
scanf("%d",&presequence[i]);
pre_value_pos[presequence[i]]=i;
}
int U,V;
for(int i=0; i<M; ++i) {
scanf("%d %d",&U,&V);
if(allNum.find(U)!=allNum.end()) {
if(allNum.find(V)!=allNum.end()) {
int left_pos,u_pos=pre_value_pos[U],v_pos=pre_value_pos[V];
left_pos=min(u_pos,v_pos);
for(int j=0; j<=left_pos; ++j) {
int test_pos=in_value_pos[presequence[j]];
int u_pos_in=in_value_pos[U],v_pos_in=in_value_pos[V];
if(test_pos>=min(u_pos_in,v_pos_in)&&test_pos<=max(u_pos_in,v_pos_in)) {
if(test_pos!=u_pos_in&&test_pos!=v_pos_in)
printf("LCA of %d and %d is %d.\n",U,V,insequence[test_pos]);
else {
if(test_pos==u_pos_in)
printf("%d is an ancestor of %d.\n",U,V);
else
printf("%d is an ancestor of %d.\n",V,U);
}
break;
}
}
} else {
printf("ERROR: %d is not found.\n",V);
}
} else {
if(allNum.find(V)!=allNum.end()) {
printf("ERROR: %d is not found.\n",U);
} else {
printf("ERROR: %d and %d are not found.\n",U,V);
}
}
}
return 0;
}