top1编程
← 返回题目
题解

二叉树问题

1 条题解

  • 0
    @ 2026-8-5 23:21:11

    P4738 二叉树问题(提高)

    解题思路

    题目给出了一棵二叉树的先序遍历序列和中序遍历序列(每个字母代表一个结点,不重复,区分大小写),要求算出这棵树的高度。输入可能有多组测试数据,要一直读到文件结束。

    先序遍历的第一个字符一定是整棵树的根结点。我们再到中序遍历序列里找到这个根的位置,根据中序遍历的性质,根左边的所有字符就是左子树的结点,根右边的所有字符就是右子树的结点。同时,在先序遍历里,紧跟根后面的那一段(长度正好等于左子树的结点个数)就是左子树的先序序列,剩下的一段就是右子树的先序序列。这样左右子树的先序、中序序列都有了,就可以递归地处理左右子树,再求出它们的高度。

    具体实现时,写一个递归函数 height(pl,pr,il,ir),表示用先序的 [pl,pr] 段和中序的 [il,ir] 段来构造子树并返回它的高度。如果区间为空(pl>pr),说明是空子树,高度为 0;否则在中序 [il,ir] 里找到根的位置 k,左子树的结点个数是 k-il,于是左子树的先序区间是 [pl+1, pl+(k-il)],右子树的先序区间是 [pl+(k-il)+1, pr],分别递归求出左右子树的高度,取较大者再加上 1(根结点自己算一层),就是整棵树的高度。以样例为例:先序 ABDFGHIEC、中序 FDHGIBEAC,根 A 的左子树有 7 个结点、高度 4,右子树只有 C、高度 1,所以整棵树高度 5。N 不超过 50,递归深度最多 50,不会栈溢出。

    参考代码

    // 二叉树问题:已知先序和中序遍历序列,求二叉树的高度(多组测试数据)
    #include <cstdio>
    char pre[55], in[55];   // 先序、中序序列
    int height(int pl,int pr,int il,int ir){
      int k,h1,h2;
      if(pl>pr) return 0;                  // 空子树高度为0
      for(k=il;k<=ir;k++)                  // 先序第一个是根,在中序里找根的位置
        if(in[k]==pre[pl]) break;
      h1=height(pl+1,pl+(k-il),il,k-1);    // 递归求左子树高度
      h2=height(pl+(k-il)+1,pr,k+1,ir);    // 递归求右子树高度
      return (h1>h2?h1:h2)+1;              // 高度=左右子树较高者+1
    }
    int main(){
      int n;
      while(std::scanf("%d",&n)==1){       // 一直读到文件结束
        std::scanf("%s%s",pre,in);
        std::printf("%d\n",height(0,n-1,0,n-1));
      }
      return 0;
    }
    

    复杂度分析

    每次递归都要在中序序列里线性查找根结点的位置,每个结点都会被当作根处理一次,每层查找花费 O(N),所以总时间是 O(N²)。空间上递归栈的深度等于树的高度,最坏情况下树退化成一条链,深度是 O(N)。N 不超过 50,运行非常快。

    • 1