PAT-A 真题 – 1151 LCA in a Binary Tree

发布于 / PAT-甲级 / 0 条评论

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进行判断,找到a和b最近的公共父亲节点。

如果a是b的父亲,输出a is an ancestor of b,反之亦然。

如果ab不存在,输出错误信息。

这道题不需要建树,根据中序序列的特征,中序序列的顺序为:左子树、根节点、右子树,可以知道,如果要判断的两个节点的位置分别位于根节点的两边,则这个根节点就是他们公共根节点,如果两个节点的位置位于根节点的同一侧,如果在左侧,说明应当往左侧继续查找,如果在右侧,则在右子树中查找。

每次查找节点的时候遍历序列会超时,使用数组存放节点位置在判断的时候会段错误(因为输入包含负数),应当使用map来存储。

代码如下:

#include <iostream>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
using namespace std;
const int maxn = 10001;
int in[maxn], pre[maxn];
map<int, int> pos;

void Judge(int preL, int preR, int inL, int inR, int a, int b){
  int root = pre[preL],
    root_pos = pos[root],
    lchild_sum = root_pos - inL,
    a_pos = pos[a],
    b_pos = pos[b];
  //递归边界 
  if(preL > preR || inL > inR) return;
  if(a_pos == root_pos) printf("%d is an ancestor of %d.\n", a, b);
  else if(b_pos == root_pos) printf("%d is an ancestor of %d.\n", b, a);
  else if((a_pos > root_pos && b_pos < root_pos) ||
      (a_pos < root_pos && b_pos > root_pos))
      printf("LCA of %d and %d is %d.\n", a, b, pre[preL]);
  //递归式
  if(b_pos < root_pos && a_pos < root_pos)  //两个节点都在左子树 
    Judge(preL+1, preL+lchild_sum, inL, root_pos-1, a, b);
  if(b_pos > root_pos && a_pos > root_pos)
    Judge(preL+lchild_sum+1, preR, root_pos+1, inR, a, b); 
}

int main(){
  int qcnt, icnt;
  cin >> qcnt >> icnt;
  for(int i = 0; i < icnt; i++){
    cin >> in[i];
    pos[in[i]] = i;  //记录对应数字在中序序列的位置 
  }
  for(int i = 0; i < icnt; i++) cin >> pre[i];
  for(int i = 0; i < qcnt; i++){
    int l,r;
    cin >> l >> r;
    bool no_l = (find(in, in + icnt, l) == in + icnt);
    bool no_r = (find(in, in + icnt, r) == in + icnt);
    if(no_l && no_r) printf("ERROR: %d and %d are not found.\n", l, r);
    else if(no_l || no_r) printf("ERROR: %d is not found.\n", no_l ? l : r);
    else Judge(0, icnt-1, 0, icnt-1, l, r);
  }
  return 0;
}

上面虽然没有建树,但是使用了和建树一样的递归方法。如果你觉得这样比较费脑子,可以牺牲一些时间复杂度,不做左右子树的判断,直接遍历每一个节点。由于先序序列是有根的前后顺序的,所以找到的公共父亲节点依然是最近的:

#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
#define MAXN 10100
//中序序列、先序序列
int inorder[MAXN] = {0}, preorder[MAXN] = {0};
//Exist非0数字表示数字所中序序列的位置,0表示不存在
map<int, int> Exist;
int QueryCnt, InputCnt;

void Judge(int n, int m){
  int m_pos = Exist[m], n_pos = Exist[n];
  for(int i = 1; i <= InputCnt; i++){
    int root_pos_in = Exist[ preorder[i] ];
    if(  m_pos < root_pos_in && n_pos > root_pos_in ||  \
      m_pos > root_pos_in && n_pos < root_pos_in  ){
        printf("LCA of %d and %d is %d.\n", n, m, preorder[i]);
        return;
      }
    else if(preorder[i] == n){
      printf("%d is an ancestor of %d.\n", n, m);
      return;
    }else if(preorder[i] == m){
      printf("%d is an ancestor of %d.\n", m, n);
      return;
    }
  }
}

int main(){
  cin >> QueryCnt >> InputCnt;
  //读取中序序列
  for(int i = 1; i <= InputCnt; i++){
    cin >> inorder[i];
    Exist[ inorder[i] ] = i;
  }
  //读取先序序列
  for(int i = 1; i <= InputCnt; i++)
    cin >> preorder[i];
  //读取判断数字
  for(int i = 0; i < QueryCnt; i++){
    int n, m;
    cin >> n >> m;
    if(!Exist[n]){
      if(!Exist[m])
        printf("ERROR: %d and %d are not found.\n", n, m);
      else printf("ERROR: %d is not found.\n", n);
      continue;
    }else{
      if(!Exist[m]){
        printf("ERROR: %d is not found.\n", m);
        continue;
      }
    }
    Judge(n, m);

  }
  return 0;
}

转载原创文章请注明,转载自: 斐斐のBlog » PAT-A 真题 – 1151 LCA in a Binary Tree
目前还没有评论,快来抢沙发吧~