PAT - 1143. Lowest Common Ancestor (30)(LCA)

The lowest common ancestor (LCA) of two nodes U and V in a tree is the deepest node that has both U and V as descendants.

A binary search tree (BST) is recursively defined as a binary tree which has the following properties:
  • The left subtree of a node contains only nodes with keys less than the node's key.
  • The right subtree of a node contains only nodes with keys greater than or equal to the node's key.
  • Both the left and right subtrees must also be binary search trees.
Given any two nodes in a BST, you are supposed to find their LCA. Input Specification: Each input file contains one test case. For each case, the first line gives two positive integers: M (<= 1000), the number of pairs of nodes to be tested; and N (<= 10000), the number of keys in the BST, respectively. In the second line, N distinct integers are given as the preorder traversal sequence of the BST. Then M lines follow, each contains a pair of integer keys U and V. All the keys are in the range of  int. Output Specification: For each given pair of U and V, print in a line "LCA of U and V is A." if the LCA is found and A is the key. But if A is one of U and V, print "X is an ancestor of Y." where X is A and Y is the other node. If U or V is not found in the BST, print in a line "ERROR: U is not found." or "ERROR: V is not found." or "ERROR: U and V are not found.". Sample Input:
6 8
6 3 1 2 5 4 8 7
2 5
8 7
1 9
12 -3
0 8
99 99
Sample Output:
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.
题目大意:给定给一个排序二叉树,即根结点的左子树中的元素的权值都比它的小,右子树都比它大。给出m个查询,每个查询有两个结点编号a和b,要求在给定的排序二叉树中找出a和b的最近的公共祖先结点。对于查询的结点,在给定的二叉树中不一定存在,用map对存在的结点进行标记即可。对于寻找LCA,如果a和b都比根结点小,那么共同祖先一定在左子树中,相反,一定在右子树中。由此我们可以写出递归函数。如果你采用遍历给定的先序遍历的序列,由此插入二叉树进行建树,会有2个测试点超时。对于LCA的查找函数,时间复杂度为O(logN),那么问题一定处在建树上,对于建树时间插入一个结点的最坏情况为O(N),那么插入N个就是就是N*N,我们可以通过对先序遍历序列排序后得到中序遍历,这样我们就可以通过先序遍历和中序遍历来建立二叉搜索树,将时间复杂度降为O(NlogN)代码中给出两种建树的方式。
#include <cstdio>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;

struct TreeNode {
	TreeNode *left, *right;
	int val;
};

// TreeNode *build (TreeNode *root, int val) {
// 	if (root == NULL) {
// 		root = new TreeNode();
// 		root->left = root->right = NULL;
// 		root->val = val;
// 	} else if (val < root->val){
// 		root->left = build(root->left, val);
// 	} else {
// 		root->right = build(root->right, val);
// 	}
// 	return root;
// }

int dfs(TreeNode *root, int a, int b) {
	if (a < root->val && b < root->val) return dfs(root->left, a, b);
	if (a > root->val && b > root->val) return dfs(root->right, a, b);
	return root->val;	
}

vector<int> pre, in;
TreeNode *build(TreeNode *root, int a, int b, int x, int y, int n) {
	if (a > b || x > y) return root;
	int i = a;
	while (in[i] != pre[x]) i++;
	if (root == NULL) {
		root = new TreeNode();
		root->left = root->right = NULL;
	}
	root->val = pre[x];
	root->left = build(root->left, a, i-1, x+1, x+1+i-1-a, n);
	root->right = build(root->right,i+1, b, x+1+i-1-a+1, y, n);
	return root;
}

int m, n, val, a, b;
map<int, int> book;

int main () {
	scanf("%d%d", &m, &n);
	TreeNode *root = NULL;
	for (int i = 0; i < n; i++) {
		scanf("%d", &val);
		book[val] = 1;
		pre.push_back(val);
		in.push_back(val);
		// root = build(root, val);
	}
	sort(in.begin(), in.end());

	root = build(root, 0, n-1, 0, n-1, n);
	// printf("%d\n", root->val);
	for (int i = 0; i < m; i++) {
		scanf("%d%d", &a, &b);
		if (book[a] == 0 && book[b] == 0) {
			printf("ERROR: %d and %d are not found.\n", a, b);
			continue;	
		}
		if (book[a] == 0) {
			printf("ERROR: %d is not found.\n", a);
			continue;
		}
		if (book[b] == 0) {
			printf("ERROR: %d is not found.\n", b);
			continue;
		}
		int LCA = dfs(root, a, b);
		if (a != LCA && b != LCA) {
			printf("LCA of %d and %d is %d.\n", a, b, LCA);
			continue;
		} 
		printf("%d is an ancestor of %d.\n", LCA, a == LCA ? b : a);
	}

	return 0;
}
 

查看原文: http://iluhao.top/archives/627
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值