PAT_甲级_1138 Postorder Traversal (25point(s)) (C++)【树的遍历/先序+中序->后序】

目录

1,题目描述

题目大意

2,思路

3,AC代码

4,解题过程

第一搏

第二搏

第三搏

第四搏


1,题目描述

Sample Input:

7
1 2 3 4 5 6 7
2 3 1 5 4 7 6

 

Sample Output:

3

题目大意

利用二叉树的先序和中序遍历,输出后序遍历的第一个节点。

 

2,思路

先序遍历+中序遍历=》后序遍历。

构建过程可以参考@&再见萤火虫&【PAT_甲级_1020 Tree Traversals (25分) (C++)【树的遍历】】

 

这里只需要输出后序遍历的第一个数字,即整棵树的第一个叶节点

用left和right限定中序遍历的左右界限,root指定先序遍历中的首节点(整棵树的根节点)

只要有左子树,就不断缩减右边界;无左子树(in[left]==pre[root])且left<right,说明仍未找到叶节点,便增加左边界,遍历右子树寻找第一个叶节点;

当左右边界重合时,便找到了第一个叶节点!

(注意,在寻找根节点pre[root]在中序遍历中的位置。以便分割子树时,可以用map记录值在中序遍历(in)中的位置,可以节省很多时间)

 

3,AC代码

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    unordered_map<int, int> inMap;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++){
        scanf("%d", &in[i]);
        inMap[in[i]] = i;
    }
    int left = 0, right = N-1, root = 0;
    while(left < right){    //left=right时 即为第一个叶节点
        int i = inMap[pre[root]];
        if(i > left){       //有左子树
            right = i - 1;
            root++;
        }else{              //无左子树 且右子树不为空
            root += (i - left + 1);
            left = i + 1;
        }
    }
    cout<<in[left];         //left=right 合并为一个节点
    return 0;
}

4,解题过程

第一搏

???这不是简化版的先序加中序-》后序吗

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++)
        scanf("%d", &in[i]);
    bool flag = false;
    int left = 0, right = N-1, root = 0;
    while(left <= right && in[right] != pre[root]){
        int i = left;
        while(i <= right && in[i] != pre[root])
            i++;
        right = i - 1;
        root++;
    }
    cout<<pre[root];
    return 0;
}

第二搏

重新考虑了一下,发现这里的逻辑有问题:

只考虑了左子树的情况,没有想到左子树为空的情况,于是改进了一下:

第三搏

这复杂度要是超时,真的没有算法可以解决了。。。

所以我怀疑是边界没处理好,陷入了死循环。。。

最终锁定这里【语句顺序写反了!!!】

#include<bits/stdc++.h>
using namespace std;
int main(){
#ifdef ONLINE_JUDGE
#else
    freopen("1.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int N, pre[50005], in[50005];
    cin>>N;
    for(int i = 0; i < N; i++)
        scanf("%d", &pre[i]);
    for(int i = 0; i < N; i++)
        scanf("%d", &in[i]);
    int left = 0, right = N-1, root = 0;

    while(left < right){
        int i = left;
        while(i <= right && in[i] != pre[root])
            i++;
        if(i > left){//有左子树
            right = i - 1;
            root++;
        }else{
            root += (i - left + 1);
            left = i + 1;
            //root += (i - left + 1); !!!此时left已经改变
        }

    }
    cout<<in[left];
    return 0;
}

622ms。。。

擦枪走火的感觉可太刺激了。。。

第四搏

突然又注意到这里查找根节点是O(N)的复杂度。。。为什么不用map记录中序遍历中各节点的位置呢?

于是

高呼666!(o゜▽゜)o☆[BINGO!]

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值