题意
给出一棵二叉树的中序和先序遍历,输入两个key a和b,求a和b的lca,即最近的祖先节点。
思路
此题参考了别人的思路。首先处理not found的情况,然后处理两个节点都在二叉树的情况。从根节点开始,
- 如果根节点在a和b之间,说明根节点就是答案
- 如果根节点是a和b中的一个,得到答案
- 如果根节点在a和b的左边,则将根节点变为右子树的根节点,重复上述过程
- 如果根节点在a和b的右边,则将根节点变为左子树的根节点,重复上述过程。
用一个map来存储每个key对应的节点在中序遍历数组中的位置。
然而用map有一个case会超时(限制为1000ms),改为unordered_map了之后就在300ms以内了,我很疑惑差距真的这么大吗?
Sample Input:
6 8
7 2 3 4 6 5 1 8
5 3 7 2 6 4 8 1
2 6
8 1
7 9
12 -3
0 8
99 99
LCA of 2 and 6 is 3.
8 is an ancestor of 1.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.
#include "bits/stdc++.h"
using namespace std;
vector<int> in,pre;
unordered_map<int,int> pos;
int t1,t2;
void lca(int rootId,int inL,int inR){
if (inL > inR ) return;
if (pre[rootId] == t1 || pre[rootId] == t2){
printf("%d is an ancestor of %d.\n",pre[rootId]==t1 ? t1:t2,pre[rootId]==t1 ? t2:t1);
} else {
int numL = pos[pre[rootId]] - inL;
int rootId_in = pos[pre[rootId]];
if (rootId_in > max(pos[t1],pos[t2])) lca(rootId+1,inL,rootId_in-1);
else if (rootId_in < min(pos[t1],pos[t2])) lca(rootId+1+numL ,rootId_in+1,inR);
else {
printf("LCA of %d and %d is %d.\n",t1,t2,pre[rootId]);
}
}
}
void lca(int a,int b){
t1 = a, t2 = b;
lca(0,0,in.size()-1);
}
int main(){
// freopen("input.txt","r",stdin);
int m, n; scanf("%d%d",&m,&n); in.resize(n), pre.resize(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 a, b; scanf("%d%d",&a,&b);
if (! pos.count(a) && ! pos.count(b)) printf("ERROR: %d and %d are not found.\n",a,b);
else if (! pos.count(a) || !pos.count(b)) printf("ERROR: %d is not found.\n",pos.count(a) ? b : a);
else lca(a,b);
}
}