题目: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)