題目描述
題目大意
給出中序序列和先序序列,再給出兩個點,求這兩個點的最近公共祖先。
分析
我的思路
這題拿到手的話,我想多數人還是有思路的,但是如何選擇一個效率高的算法是關鍵。
我的想法是先“建樹”,但是這個樹結點的數據結構中的指針域存放的是其父結點的地址,這樣便於我們找到某結點的祖先。
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<unordered_set>
#include<unordered_map>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int pre[10000], in[10000];
struct node {
int val;
node *fa;
};
unordered_map<int, node*> mapp; //數據域與結點地址的映射
void create(node* fa,int prel, int prer, int inl, int inr) {
if (prel > prer) return;
node *now = new node;
now->val = pre[prel]; now->fa = fa;
mapp[now->val] = now;
int k=inl;
while (k <= inr && in[k] != pre[prel]) k++;
int numl = k - inl;
create(now, prel + 1, prel + numl, inl, k - 1);
create(now, prel + numl + 1,prer, k + 1, inr);
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif
int m, n; scanf("%d%d", &m, &n);
for (int i = 0; i < n; i++) scanf("%d", &in[i]);
for (int i = 0; i < n; i++) scanf("%d", &pre[i]);
create(NULL, 0, n - 1, 0, n - 1);
while (m--) {
int u, v;
scanf("%d%d", &u, &v);
if (mapp.count(u) == 0 && mapp.count(v) == 0) {
printf("ERROR: %d and %d are not found.\n",u,v);
}
else if (mapp.count(u) == 0||mapp.count(v)==0) {
printf("ERROR: %d is not found.\n", mapp.count(u) == 0 ? u : v);
}
else {
node *a = mapp[u], *b = mapp[v];
vector<int> path1, path2; //存放從該結點一直到根節點的路徑
while (a) {
path1.push_back(a->val);
a = a->fa;
}
while (b) {
path2.push_back(b->val);
b = b->fa;
}
int ances = 0, i = path1.size() - 1, j = path2.size() - 1;
for (; i >= 0 && j >= 0; i--, j--) {
if (path1[i] != path2[j]) {
ances = path1[i + 1]; break;
}
}
if (i < 0) ances = u;
if (j < 0) ances = v;
if (ances == u || ances == v) {
printf("%d is an ancestor of %d.\n", ances, ances == u ? v : u);
}
else printf("LCA of %d and %d is %d.\n", u, v, ances);
}
}
return 0;
}
柳神思路
看了柳神的思路,思路更加簡潔,效率更高。
由於中序遍歷給出的順序是“左子樹——根節點——右子樹”,而題目給定的每個結點的key是唯一的,那麼在遞歸過程中,通過找到結點在中序遍歷的位置,就可以通過遞歸找到LCA。
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<stack>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
unordered_map<int, int> pos;
int in[10000], pre[10000], u, v;
void dfs(int inl, int inr, int prel, int prer) {
if (prel > prer) return;
int posroot = pos[pre[prel]], posu = pos[u], posv = pos[v];
int numl = posroot - inl;
if (posu<posroot&&posv>posroot || posu > posroot&&posv < posroot)
printf("LCA of %d and %d is %d.\n", u, v, pre[prel]);
else if (posu < posroot&&posv < posroot)
dfs(inl, posroot - 1, prel + 1, prel + numl);
else if (posu > posroot&&posv > posroot)
dfs(posroot + 1, inr, prel + numl + 1, prer);
else if (posu == posroot || posv == posroot)
printf("%d is an ancestor of %d.\n", pre[prel], posu == posroot ? v : u);
}
int main() {
#ifdef ONLINE_JUDGE
#else
freopen("1.txt", "r", stdin);
#endif
int m, n; cin >> m >> 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]);
while (m--) {
scanf("%d%d", &u, &v);
if (pos.count(u) == 0 && pos.count(v) == 0) printf("ERROR: %d and %d are not found.\n",u,v);
else if (pos.count(u) == 0 || pos.count(v) == 0)
printf("ERROR: %d is not found.\n", pos.count(u)==0 ? u : v);
else dfs(0, n - 1, 0, n - 1);
}
return 0;
}