PAT甲级1151 LCA in a Binary Tree
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.
Given any two nodes in a binary tree, 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 (≤ 1,000), the number of pairs of nodes to be tested; and N (≤ 10,000), the number of keys in the binary tree, respectively. In each of the following two lines, N distinct integers are given as the inorder and preorder traversal sequences of the binary tree, respectively. It is guaranteed that the binary tree can be uniquely determined by the input sequences. 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 binary tree, 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
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
结尾无空行
Sample Output:
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.
结尾无空行
下面代码基本是柳神代码修改而来
这一题的主要思想是不需要构建树,只需要根据先序和中序确定的唯一树进行查询即可
假设查询数字为a和b,使用先序遍历查询,有以下情况:
1、a或b不出现在树中,输出error
2、a和b在树中的所在位置为根节点的左右子树,那么此时最小公共祖先节点就是该根节点
3、a或b为此时的根节点,那么此时a或b为另一个节点的最小公共节点
4、a和b位于根节点的左子树,那么就将根节点设置为左子树根节点,进行递归
5、a和b位于根节点的右子树,那么就将根节点设置为右子树根节点,进行递归
这里主要是超时问题,测试点4会出现超时,出错原因:
lca函数中需要提前将a,b,root在中序所在位置存入局部变量,然后在条件中使用这些局部变量,而不是每进行一次判断就在map里进行查询,这样会超时
这一题其实不管是先序遍历还是中序遍历查询(例如是柳神代码里的)都是可以通过的,超时原因不在于这里
思想
根据先序序列和中序序列可以得到一颗唯一的二叉树,中序序列是左中右,因此只要判断查询节点是否位于中序序列的根节点两边即可
步骤
1、记录中序序列和先序序列,记录每个值对应所在中序的位置
2、lca中判断当前a和b所在中序的位置,是否下标大于小于当前树的根节点,又或是等于
3、如果不是,那就看是位于左子树还是右子树,然后在各自子树找
#include <iostream>
#include <vector>
#include <map>
using namespace std;
vector<int> pre;
vector<int> in;
map<int, int> pos_in;
int flag = 0;
void lca(int a, int b, int s1, int e1, int s2, int e2) {
if (s1 > e1 || s2 > e2) {
return;
}
int a_pos = pos_in[a], b_pos = pos_in[b], rootidx = pos_in[pre[s1]];
if ((a_pos < rootidx && b_pos > rootidx) || (a_pos > rootidx && b_pos < rootidx)) {
printf("LCA of %d and %d is %d.\n", a, b, pre[s1]);
return;
}
else if (a_pos == rootidx) {
printf("%d is an ancestor of %d.\n", a, b);
return;
}
else if (b_pos == rootidx) {
printf("%d is an ancestor of %d.\n", b, a);
return;
}
else if (a_pos < rootidx && b_pos < rootidx) {
lca(a, b, s1 + 1, rootidx - s2 + s1, s2, rootidx - 1);
}
else if (a_pos > rootidx && b_pos > rootidx) {
lca(a, b, rootidx - s2 + s1 + 1, e1, rootidx + 1, e2);
}
}
int main() {
int m, n;
cin >> m >> n;
pre.resize(n);
in.resize(n);
for (int i = 0; i < n; ++i) {
cin >> in[i];
pos_in[in[i]] = i;
}
for (int i = 0; i < n; ++i) {
cin >> pre[i];
}
for (int i = 0; i < m; ++i) {
int a, b;
cin >> a >> b;
flag = 0;
if (pos_in.find(a) == pos_in.end() && pos_in.find(b) == pos_in.end()) {
printf("ERROR: %d and %d are not found.\n", a, b);
}
else if (pos_in.find(a) == pos_in.end()) {
printf("ERROR: %d is not found.\n", a);
}
else if (pos_in.find(b) == pos_in.end()) {
printf("ERROR: %d is not found.\n", b);
}
else {
lca(a, b, 0, n - 1, 0, n - 1);
}
}
return 0;
}
先序遍历确定一颗唯一的二叉搜索树
主要思路和上面类似,只不过是从位置大小转变为数值大小:
1、a或b不出现在树中,输出error
2、a大于根节点且b小于根节点,或a小于根节点且b大于根节点(其实意思就是a和b在二叉搜索树的根节点的两侧),那么此时最小公共祖先节点就是该根节点
3、a或b为此时的根节点,那么此时a或b为另一个节点的最小公共节点
4、其余情况则继续遍历先序序列中的下一个数
#include <iostream>
#include <vector>
#include <map>
using namespace std;
vector<int> pre;
map<int,int> pos;
int n;
void lca(int a,int b,int s1){
if((a < pre[s1]&&b > pre[s1])||(a > pre[s1]&&b < pre[s1])){
printf("LCA of %d and %d is %d.\n",a,b,pre[s1]);
}
else if(a == pre[s1]){
printf("%d is an ancestor of %d.\n",a,b);
}
else if(b == pre[s1]){
printf("%d is an ancestor of %d.\n",b,a);
}
else{
lca(a,b,s1 + 1);
}
}
int main(){
int m;
cin >> m >> n;
pre.resize(n);
for(int i = 0;i < n;++i){
cin >> pre[i];
pos[pre[i]] = i;
}
for(int i = 0;i < m;++i){
int a,b;
cin >> a >> b;
if(pos.find(a) == pos.end()&&pos.find(b) == pos.end()){
printf("ERROR: %d and %d are not found.\n",a,b);
}
else if(pos.find(a) == pos.end()){
printf("ERROR: %d is not found.\n",a);
}
else if(pos.find(b) == pos.end()){
printf("ERROR: %d is not found.\n",b);
}
else{
lca(a,b,0);
}
}
return 0;
}