题目链接:PAT【甲级】1151
题目简述:给定一个二叉树的中序遍历序列和前序遍历序列,序列由二叉树的各节点值构成,且各节点值不同。数值在int
表示范围内。然后问:给定的两个值,是否是节点值?如果是,那么他们的最近公共祖先的节点值是多少?
#include<bits/stdc++.h>
using namespace std;
vector<int> preOrder(10001), inOrder(10001);
unordered_map<int, int> indexm;
void getLCA(int l, int r, int pivot, int c1, int c2){
int pos = indexm[preOrder[pivot]];
int c1_pos = indexm[c1], c2_pos = indexm[c2];
if(c1_pos == pos || c2_pos == pos)
printf("%d is an ancestor of %d.\n", c1_pos == pos ? c1 : c2, c2_pos == pos ? c1 : c2);
else if(c1_pos < pos && c2_pos < pos)
getLCA(l, pos - 1, pivot + 1, c1, c2);
else if(c1_pos < pos && c2_pos > pos || c1_pos > pos && c2_pos < pos)
printf("LCA of %d and %d is %d.\n", c1, c2, preOrder[pivot]);
else if(c1_pos > pos && c2_pos > pos)
getLCA(pos + 1, r, pivot + (pos - l) + 1, c1, c2);
}
int main(){
int N, M;
cin >> M >> N;
for (int i = 1; i <= N;i++){
cin >> inOrder[i];
indexm[inOrder[i]] = i;
}
for (int i = 1; i <= N;i++)
cin >> preOrder[i];
while(M--){
int c1, c2;
cin >> c1 >> c2;
if(indexm[c1] == 0 && indexm[c2] == 0)
printf("ERROR: %d and %d are not found.\n", c1, c2);
else if(indexm[c1] == 0 || indexm[c2] == 0)
printf("ERROR: %d is not found.\n", indexm[c1] == 0 ? c1 : c2);
else
getLCA(1, N, 1, c1, c2);
}
return 0;
}
刚开始读这道题,一下子就想到了去重构二叉树,然后记录一个Father数组,再记录一个标记数组,当当前访问father数组中的值对应的标记数组中标志已访问过,那么这个就是公共祖先。
但是这里有个问题,重构二叉树时,不好去记录前后父子关系。后来就想有没有什么好的解决办法?最后就观察到这样的特征:中序遍历很特殊,他可以把二叉树分成一段一段的,如果要求的两个节点是分开的,那么他们之间的某个节点便是答案节点。而这个节点得通过前序遍历来求,因为前序是根左右
的形式。这样便有了如上代码的形式。
但是这边有个坑,那就是查询区间的限定。稍微有点绕,后来阅读了柳神的代码,自己又想了一下,才通透了。对了,原来printf才是最好用的,学到了!!
这个代码的核心应该是区间的限定吧。