• Preorder and Inorder(先序遍历+中序遍历求二叉树)


    题意

    给定一棵二叉树的先序遍历\(P\)和中序遍历\(I\),求二叉树。(节点数为\(N\)

    题目链接:https://atcoder.jp/contests/abc255/tasks/abc255_f

    数据范围

    \(2 \leq N \leq 2 \times 10^5\)

    思路

    这道题思路非常经典,国内高校《数据结构》课都会学到。因此,在这里不详细阐述算法过程,只讲解代码的编写。

    首先用一个数组Iinv记录每个节点在中序遍历中的下标,然后使用dfs(s, t, S, T)递归求解问题。其中s和t表示当前考虑的先序遍历的范围,S和T表示当前考虑的中序遍历的范围。

    首先找到根节点r = P[s]以及在中序遍历的下标p = Iinv[r]

    如果存在左子树if(p - S > 0),则左儿子是P[s + 1];如果存在右子树if(T - p > 0),则右儿子是P[s + p - S + 1](因为左子树有\(p - S\)个节点,因此右儿子是先序遍历中s之后的第\(p - S + 1\)个节点)。

    因此,左子树的在先序遍历中的范围是\([s + 1, s + p - S]\);右子树的范围是\([s + p - S + 1, t]\)。递归求解即可。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int N = 200010;
    
    int n;
    int P[N], I[N], Iinv[N];
    int L[N], R[N];
    
    bool dfs(int s, int t, int S, int T)
    {
        int r = P[s], p = Iinv[r];
        if(p < S || T < p) return false;
        if(p - S > 0) {
            L[r] = P[s + 1];
            if(!dfs(s + 1, s + p - S, S, p - 1)) return false;
        }
        if(T - p > 0) {
            R[r] = P[s + p - S + 1];
            if(!dfs(s + p - S + 1, t, p + 1, T)) return false;
        }
        return true;
    }
    
    int main()
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++) scanf("%d", &P[i]);
        for(int i = 1; i <= n; i ++) scanf("%d", &I[i]);
        for(int i = 1; i <= n; i ++) Iinv[I[i]] = i;
        if(P[1] != 1 || !dfs(1, n, 1, n)) {
            printf("-1\n");
            return 0;
        }
        for(int i = 1; i <= n; i ++) printf("%d %d\n", L[i], R[i]);
        return 0;
    }
    
  • 相关阅读:
    IOS -- 获取本地图片和网络图片的大小size
    xib中的label加边框
    iOS开发之Masonry框架源码深度解析
    10分钟搭建 App 主流框架
    卸载服务器GitLab
    linux安装git方法
    虚拟机安装centos7, 再安装gitlab 简单步骤
    collectionView 防止cell复用的方法
    UIButton 设置图片文字垂直居中排列
    button获取验证码60秒倒计时 直接用
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/16371052.html
Copyright © 2020-2023  润新知