F. 二叉搜索树的最近公共祖先时间限制1s

题目描述

给定一棵二叉搜索树的先序遍历序列,要求你找出任意两结点的最近公共祖先结点(简称 LCA)。

输入

输入的第一行给出两个正整数:待查询的结点对数 M(≤ 1 000)和二叉搜索树中结点个数 N(≤ 10 000)。随后一行给出 N 个不同的整数,为二叉搜索树的先序遍历序列。最后 M 行,每行给出一对整数键值 U 和 V。所有键值都在整型int范围内。

输出

对每一对给定的 U 和 V,如果找到 A 是它们的最近公共祖先结点的键值,则在一行中输出 LCA of U and V is A.。但如果 U 和 V 中的一个结点是另一个结点的祖先,则在一行中输出 X is an ancestor of Y.,其中 X 是那个祖先结点的键值,Y 是另一个键值。如果 二叉搜索树中找不到以 U 或 V 为键值的结点,则输出 ERROR: U is not found. 或者 ERROR: V is not found.,或者 ERROR: U and V are not found.

输入样例

6 8
6 3 1 2 5 4 8 7
2 5
8 7
1 9
12 -3
0 8
99 99

输出样例

 LCA of 2 and 5 is 3.
8 is an ancestor of 7.
ERROR: 9 is not found.
ERROR: 12 and -3 are not found.
ERROR: 0 is not found.
ERROR: 99 and 99 are not found.

思路分析

首先判断u和v是否在树中。有不在的就输出ERROR的三种情况之一。

若都在树中, 把每个结点的所有父亲都用数组或队列存起来。若u和v都在树中,找u的父亲中有没有v。输出 X is an ancestor of Y.,其中 X 是那个祖先结点的键值,Y 是另一个键值。没有就u和v父亲数组中相同的元素,倒着找,找到的就是最近的公共祖先。那么问题来了,如何找到每个结点的父亲呢?因为给出的是二叉搜索树先序遍历的结果,所以第一个是根,第二个到比他大的数之前的都是左子树,比他大的到最后都是右子树。那么第二个到最后一个都可以添加一个父亲,添加根。再递归地遍历左子树和右子树,树种除了根的每一个结点都把根结点当作父亲。

AC代码 

#include<iostream>
#include<queue>
using namespace std;
int a[100];
queue<int> parent[100];
int n;
int find(int x) {
	for (int i = 0; i < n; i++) {
		if (a[i] == x) return 1;
	}
	return 0;
}
void if_tree(int start, int end) {
	if (start >= end) return ;
	for (int i = start + 1; i < end; i++)
		parent[i].push(a[start]);
		
	int center = start + 1;
	while (a[center] < a[start]) {
		if (center >= n) break;
		center++;
	}
	if_tree(center, end);  //右子树
	if_tree(start + 1, center); //左子树
	return ;
}
int main() {
	int m, u, v;
	cin >> m >> n;
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	while (m--) {
		cin >> u >> v;
		int find1 = 0, find2 = 0;
		find1 = find(u);
		find2 = find(v);
		if (find1 + find2 == 0) {
			cout << "ERROR: " << u << " and " << v << " are not found." << endl;
		} else if (find1 == 0 && find2 == 1) {
			cout << "ERROR: " << u << " is not found." << endl;
		} else if (find1 == 1 && find2 == 0) {
			cout << "ERROR: " << v << " is not found." << endl;
		} else {
			if_tree(0,n);
			int tag=0;
			int uindex, vindex;
			for (int i = 0; i < n; i++) {
				if (u == a[i]) uindex = i;
				if (v == a[i]) vindex = i;
			}
			queue<int> uu = parent[uindex];
			queue<int> vv = parent[vindex];
			int usize = uu.size();
			int vsize = vv.size();
		//	cout<<"u有几个父亲:"<<usize<<endl;
		//	cout<<"v有几个父亲:"<<vsize<<endl; 
	
			while (!parent[uindex].empty()) {
				if (parent[uindex].front() == v) {
					tag = 1;
					break;
				}
				parent[uindex].pop();
			}
			while (!parent[vindex].empty()) {
				if (parent[vindex].front() == u) {
					tag = 2;
					break;
				}
				parent[vindex].pop();
			}
			if (tag == 1) {
				cout << v << " is an ancestor of " << u << "." << endl;
			} else if (tag == 2) {
				cout << u << " is an ancestor of " << v << "." << endl;
			} else {
				int uuu[usize];
				for (int i = 0; i < usize; i++) {
					uuu[i] = uu.front();
					uu.pop();
				}
			
				int vvv[vsize];
				for (int i = 0; i < vsize; i++) {
					vvv[i] = vv.front();
					vv.pop();
				}
				int tag = 0, result;
				for (int i = usize - 1; i >= 0; i--) {
					for (int j = vsize - 1; j >= 0; j--) {
						if (uuu[i] == vvv[j]) {
							result = uuu[i];
							tag = 1;
							break;
						}
					}
					if (tag == 1) break;
				}
				cout << "LCA of " << u << " and " << v << " is " << result << "." << endl;
			}
		}
	}
	return 0;
}

有问题欢迎指正!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值