18年秋季第四題 PAT甲級 1151 LCA in a Binary Tree (30分)

題目來源:https://pintia.cn/problem-sets/994805342720868352/problems/1038430130011897856

備考彙總貼:2020年3月PAT甲級滿分必備刷題技巧

題目

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.

題目大意

給定中序、前序遍歷序列,找最近公共祖先,相當於找兩個子輩在族譜裏面輩分最低的共同祖先。

題目分析

1.輸出有幾種?
題目寫出的有四種:兩個都找不到、其中一個找不到、其中一個是LCA、有LCA。
但是還有個隱藏的邊界:如果給出的兩個數是相同的,是屬於“其中一個是LCA”。這個知識點是學習LCA的必須掌握的。

2.LCA

解題方法

這道題有兩個思路:

第一個思路就是看兩個值在root的哪邊:

  • 兩個值都在左邊,則LCA在左邊
  • 兩個值都在右邊,則LCA在右邊
  • 一個在左一個在右,則說明LCA就是當前的root節點
  • 其餘的情況只能是一個正好是另一個的根節點,則LCA就是這個root節點

第一個思路的滿分代碼(從liuchuo博客複製,僅做了語句的排版)

#include <iostream>
#include <vector>
#include <map>
using namespace std;
map<int, int> pos;
vector<int> in, pre;
void lca(int inl, int inr, int preRoot, int a, int b) {
    if (inl > inr) return;
    int inRoot = pos[pre[preRoot]], aIn = pos[a], bIn = pos[b];
    if (aIn < inRoot && bIn < inRoot)//兩個值都在左邊,則LCA在左邊
        lca(inl, inRoot-1, preRoot+1, a, b);
    else if (aIn > inRoot && bIn > inRoot)//兩個值都在右邊,則LCA在右邊
        lca(inRoot+1, inr, preRoot+1+(inRoot-inl), a, b);
    else if ((aIn < inRoot && bIn > inRoot) || (aIn > inRoot && bIn < inRoot))//一個在左一個在右,則說明LCA就是當前的root節點
        printf("LCA of %d and %d is %d.\n", a, b, in[inRoot]);
    else if (aIn == inRoot)
        printf("%d is an ancestor of %d.\n", a, b);
    else if (bIn == inRoot)
        printf("%d is an ancestor of %d.\n", b, a);
}
int main() {
    int m, n, a, b;
    scanf("%d %d", &m, &n);
    in.resize(n + 1);
    pre.resize(n + 1);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &in[i]);
        pos[in[i]] = i;
    }
    for (int i = 1; i <= n; i++) scanf("%d", &pre[i]);
    for (int i = 0; i < m; i++) {
        scanf("%d %d", &a, &b);
        if (pos[a] == 0 && pos[b] == 0)
            printf("ERROR: %d and %d are not found.\n", a, b);
        else if (pos[a] == 0 || pos[b] == 0)
            printf("ERROR: %d is not found.\n", pos[a] == 0 ? a : b);
        else
            lca(1, n, 1, a, b);
    }
    return 0;
}

第二種思路則需要建樹+標記節點的父節點:

1.根據先序和中序確定每個結點的父親結點及層數;
2.將低的層次的點回溯到對應高層次的祖先結點,再依據值進行判斷或回溯。

第二種思路滿分代碼(代碼轉載自csdn網友

#include<iostream>
#include<map>
#include<algorithm>
using namespace std;
#define MAX 10005
int pre[MAX],in[MAX];
typedef struct node{
    int lev,par;
}node;
map<int,node>arr;//int 的高度和父親
void CreatTree(int inL,int inR,int preL,node no)//中序先序建後序
{
    if(inL>inR)return;
    int i=inL;
    while(in[i]!=pre[preL])++i;//中序中根節點位置
    arr[pre[preL]]=no;
    ++no.lev;no.par=pre[preL];
    CreatTree(inL,i-1,preL+1,no);
    CreatTree(i+1,inR,preL+i-inL+1,no);//先序中右子樹根節點爲  當前根節點位置+左子樹個數+1
}
int main()
{
    freopen("test.txt","r",stdin);
    int i,N,M;
    scanf("%d %d",&M,&N);
    for(i=0;i<N;++i)scanf("%d",&in[i]);
    for(i=0;i<N;++i)scanf("%d",&pre[i]);
    node no;no.lev=0;no.par=-1;
    CreatTree(0,N-1,0,no);
    while(M--){
        int a,b;
        scanf("%d %d",&a,&b);
        if(!arr.count(a)&&!arr.count(b))printf("ERROR: %d and %d are not found.\n",a,b);//沒有a,b結點
        else if(!arr.count(a)||!arr.count(b))printf("ERROR: %d is not found.\n",arr.count(a)?b:a);//沒有其中一個結點
        else if(a==b)printf("%d is an ancestor of %d.\n",a,b);//同一結點
        else{
            int x=a,y=b;
            while(arr[a].lev<arr[b].lev)b=arr[b].par;//b回溯到與a同一層,
            if(b==a){printf("%d is an ancestor of %d.\n",a,y);continue;}//a是b祖先
            while(arr[b].lev<arr[a].lev)a=arr[a].par;//a回溯到與b同一層
            if(b==a){printf("%d is an ancestor of %d.\n",b,x);continue;}//b是a祖先
            while(b!=a){a=arr[a].par;b=arr[b].par;}//一起回溯。
            printf("LCA of %d and %d is %d.\n",x,y,a);
        }
    }
    return 0;
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章