NC204382 中序序列

题目

题目描述

给定一棵有 \(n\) 个结点的二叉树的先序遍历与后序遍历序列,求其中序遍历序列。
若某节点只有一个子结点,则此处将其看作左儿子结点

示例1

输入

5,[3,2,1,4,5],[1,5,4,2,3]

返回值

[1,2,5,4,3]

说明

img

备注

\(1 \leq n \leq 100,000\)

题解

知识点:树,递归。

通常通过先序和后序的组合是无法确定一棵二叉树的,因为根左右和左右根都无法划分左右子树。而本题确定了第一个子节点必然是左孩子,即左子树根节点,那么通过第一个子节点可以确定左右子树。

先通过先序找到根节点和第一个左子树根节点,然后在后序找到左子树根节点位置,其必然在后序左子树区间的最右端。因此,后序的最左端到这个节点的所有节点都是左子树的,而剩下的除了根节点都是右子树的。于是,左右子树划分完成,可以递归实现。

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

vector<int> fo, lo;

void io(int l1, int r1, int l2, int r2) {
    if (l1 > r1) return;
    if (l1 == r1) {
        cout << fo[l1] << ' ';
        return;
    }
    int pos = -1;
    for (int i = l2;i <= r2;i++) if (lo[i] == fo[l1]) pos = i;
    io(l1 + 1, l1 + 1 + (pos - l2), l2, pos);
    cout << fo[l1] << ' ';
    io(l1 + 1 + (pos - l2) + 1, r1, pos + 1, r2 - 1);
}


int main() {
    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 0, tmp;i < n;i++) cin >> tmp, fo.push_back(tmp);
    for (int i = 0, tmp;i < n;i++) cin >> tmp, lo.push_back(tmp);
    io(0, n - 1, 0, n - 1);
    return 0;
}
posted @ 2022-06-23 10:51  空白菌  阅读(35)  评论(0编辑  收藏  举报