【PAT甲级】1119 Pre- and Post-order Traversals(前序后序转中序)

【题目链接】

 

【题意】

根据二叉树的前序和后序序列,如果中序序列唯一,输出Yes,如果不唯一输出No,并输出这个中序序列。

 

【题解】

众所周知,二叉树是不能够根据前序和中序建立的,为什么呢?首先需要明确先序序列的遍历顺序是:根左右,后序序列的遍历顺序是:左右根。

然后我们来说一下这个样例(为了更好的说明不唯一性,没有用题目给出的样例):

前序:1 4 6 3 2 5 7

后序:3 6 4 5 7 2 1

首先1肯定是整棵二叉树的根节点,然后根据前序序列我们可以知道4是1的子树(此时还不确定是左子树还是右子树),然后可以得到在后序序列中4的位置,由于后序序列的遍历顺序是左右根,那么很容易可以确定3和6肯定是4的子节点,这个时候我们可以知道已4为根节点的子节点有2个(代码中也就是num),然后到前序序列去算,发现prer-prel - 1(也就是去掉1 4 )发现大于num,由于前序遍历序列是根左右,所以prer - prel -1 - num > 0不就说明去掉左子树之外还存在节点嘛,那我们刚才的以4为根节点的树就是1的左子树,2 5 7即是右子树。

然后我们继续递归(也就是说把刚才的序列分成左区间(前序 4 6 3 后序 3 6 4)和右区间(前序2 5 7 后序5 7 2)),然后我们来看左子树吧,这时候可以知道6是4的子树,到后序序列里找到6,那么可以确定3是6的子节点,这时我们可以知道以6位根节点的子节点有1个,然后发现前序序列中也只有1个3,这时候我们就无法确定6是4的左子树还是右子树了。

【代码】

#include<bits/stdc++.h>
using namespace std;
const int maxn = 35;
int pre[maxn], post[maxn];
int f = 1;
vector<int>v;
void getorder(int prel, int prer, int postl, int postr)
{
    if (prel == prer)
    {
        v.push_back(pre[prel]);
        return;
    }
    int a = pre[prel + 1];
    int postidx = postl;
    while(post[postidx] != a && postidx <= postr)postidx++;
    int num = postidx - postl;//以a为根节点的子树的节点数
    if (prer - prel - 1 == num)f = 0;
    
    /*在前序序列中,如果以pre[prel]为根节点的子树的节点数-a这个节点等于num,4
    那么久无法判断a是在pre[prel]的左子树还是右子树,这里我们默认为左子树*/
    getorder(prel + 1, prel + num + 1, postl, postidx);
    
    v.push_back(pre[prel]);
    
    /*在前序序列中,如果以pre[prel]为根节点的子树的节点数-a这个节点大于num,
    因为前序的遍历序列是根左右,那么就说明以pre[prel]为根的树还有右子树*/
    if (prer - prel  - 1> num)
        getorder(prel + num + 2, prer, postidx + 1, postr - 1);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d", &pre[i]);
    for (int i = 0; i < n; i++)
        scanf("%d", &post[i]);
    getorder(0, n - 1, 0, n - 1);
    if(f)printf("Yes\n");
    else printf("No\n");
    printf("%d", v[0]);
    for (int i = 1; i < n; i++)
        printf(" %d", v[i]);
    printf("\n");
}

 

posted @ 2019-08-17 19:09  牛肉叉烧饭w  阅读(383)  评论(0编辑  收藏  举报
levels of contents