PAT 1119. Pre- and Post-order Traversals (30) (根据前序后序求中序)

题意:给你一棵树的前序和后序遍历,问你它的中序遍历是否唯一,并且给出任意一种中序遍历。


思路:判断中序遍历是否唯一,我们可以通过每个非叶子节点是否都是有两个孩子,如果只有一个孩子,那他的子树既可以是左子树又可以是又子树,所以就不唯一了。


那怎么判断是否有只有一个孩子的结点。

可以看看这个博客:点击打开链接

已知前序遍历和后序遍历序列,是无法确定一棵二叉树的,原因在于如果只有一棵子树可能是左孩子也有可能是右孩子。由于只要输出其中一个方案,所以假定为左孩子即可。下面就是如何根据前序和后序划分出根节点和左右孩子,这里需要定义前序和后序的区间范围,分别为[preL,preR],[postL,postR]。  

  一开始区间都为[1,n],可以发现前序的第一个和后序的最后一个为根节点root,前序的第二个值val为其某子树的根节点(但还无法确定是左孩子or右孩子)。在后序中找对应的值所在的位置postIdx,则postIdx之前的节点均为val的孩子节点,统计其个数num。那么我们就可以划分区间:  

若num个数=preR-preL-1,即val后面的个数都是其子节点,那么二叉树不唯一,将其作为root的左子树处理。

否则划分为左子树区间和右子树对应的前序和后序区间,顺便更新下root的左孩子preL+1,右孩子preL+num+2:
preOrder:[preL+1,preL+num+1],postOrder:[postL,postIdx];
preOrder:[preL+num+2,preR],postOrder:[postIdx+1,postR-1];
然后递归划分即可


拿样例举例:
1 (2) [3 {4 6 7} <5>]
(2) [{6 7 4} <5> 3] 1
不同的括号对应不同的子树区间
第一次递归划分了(2)-(2),[3 4 6 7 5]-[6 7 4 5 3]
由于(2)只有一棵,不继续划分。
第二次递归划分了{4 6 7}-{6 7 4},<5>-<5>
第三次递归划分了(6)-(6),(7)-(7)


代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 35;
int n, cnt, pre[maxn], in[maxn], post[maxn];
bool isUnique;

void build(int preL, int preR, int postL, int postR)
{
    if(preL == preR) { in[cnt++] = pre[preL]; return ; }
    if(preL > preR) return ;
    int idx;
    for(int i = postL; i < postR; i++)
    {
        if(pre[preL+1] == post[i])
        {
            idx = i;
            break;
        }
    }
    int numL = idx-postL;
    if(preR-preL-1 == numL) isUnique = 0;
    build(preL+1, preL+1+numL, postL, idx);
    in[cnt++] = pre[preL];
//    cout << pre[preL] << endl;
    build(preL+numL+2, preR, idx+1, postR-1);
}

int main(void)
{
    while(cin >> n)
    {
        cnt = 1;
        isUnique = 1;
        for(int i = 1; i <= n; i++) scanf("%d", &pre[i]);
        for(int i = 1; i <= n; i++) scanf("%d", &post[i]);
        build(1, n, 1, n);
        puts(isUnique ? "Yes" : "No");
        for(int i = 1; i <= n; i++) printf("%d%c", in[i], i==n ? '\n' : ' ');
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值