P1030 求先序排列

题目:https://www.luogu.com.cn/problem/P1030

给出一棵二叉树的中序和后序,输出它的先序(结点用不同的大写字母表示,长度<=8)

先序遍历:[根 [左子树先序遍历结果] [右子树先序遍历结果]]
中序遍历:[[左子树中序遍历结果] 根 [右子树中序遍历结果]]
后序遍历:[[左子树后序遍历结果] [右子树后序遍历结果] 根]

首先确定根结点:在后序遍历中,最后一个是根结点,
在中序遍历中找到根结点,建立左子树,建立右子树,
至于如何建立左子树和右子树?请重新再读一遍这段话。

由题目知,结点互不相同,于是建立一个映射idx,直接在中序遍历中找到根的位置(当然也可以直接for循环遍历一遍中序遍历 ,找到 根 的位置)

在中序遍历中找到根的位置m后,如果m不在中序遍历的开头,那么说明这个根结点是有左子树的,如果m不在中序遍历的末尾,说明这个根结点是有右子树的。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<unordered_map>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 7;
string in_order, post_order;
unordered_map<char, int> idx;
// [l1, r1]为中序遍历in_order的区间, [l2, r2]为后序遍历post_order的区间
void print(int l1, int r1, int l2, int r2)
{
    char root = post_order[r2];
    cout << root;
    int m = idx[root];
    if(m > l1) print(l1, m - 1, l2, r2 - r1 + m - 1);  // m有左子树
    if(m < r1) print(m + 1, r1, l2 - m + l1, r2 - 1);  // m有右子树
	
	/*
	 m有左子树,其左子树的中序遍历的区间为[l1, m - 1], 左子树的后序遍历区间为[l2, r2 - (r1 - m) - 1],其中(r1-m)为m的右子树的长度
	 m有右子树,其右子树的中序遍历的区间为[m + 1, r1], 右子树的后序遍历区间为[l2 + (m - l1), r2 - 1],其中(m-l1)为m的左子树的长度
	*/
}
int main()
{
    cin >> in_order >> post_order;
    int len = in_order.length();
    for(int i = 0; i < len; i++) idx[in_order[i]] = i;
    print(0, len - 1, 0, len - 1);
    cout << endl;
    return 0;
}


复杂度

  • 时间复杂度:O(n),n为结点个数
  • 空间复杂度:O(n),需要O(n)的空间存储哈希映射,以及O(h)(h为树的高度)的空间来表示递归时栈的空间,这里h<n,所以总空间复杂度为O(n)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值