1151 LCA in a Binary Tree (30分)

題目描述

在這裏插入圖片描述
在這裏插入圖片描述

題目大意

給出中序序列和先序序列,再給出兩個點,求這兩個點的最近公共祖先。

分析

我的思路

  這題拿到手的話,我想多數人還是有思路的,但是如何選擇一個效率高的算法是關鍵。
  我的想法是先“建樹”,但是這個樹結點的數據結構中的指針域存放的是其父結點的地址,這樣便於我們找到某結點的祖先。

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章