瑞文考研算法每日一题—2023.06.04 从中序与后序遍历序列构造二叉树

在这里插入图片描述

Problem: 106. 从中序与后序遍历序列构造二叉树

方法一:递归

思路

后序遍历的顺序是 [ [ 左子树 ] , [ 右子树 ] ,根节点 ] [[左子树],[右子树],根节点] [[左子树],[右子树],根节点]

中序遍历的顺序是 [ [ 左子树 ] , 根节点 , [ 右子树 ] ] [[左子树],根节点,[右子树]] [[左子树],根节点,[右子树]]

由于二叉树的定义具有递归性质,我们可以通过递归的方式去构造二叉树。

  1. 我们知道后序遍历的最后一个结点是根节点,其在中序遍历的对应位置记为 i n d e x index index。通过 v a l val val去寻找值需要 O ( n ) O(n) O(n)的时间复杂度,我们可以用一个哈希表 m m m提前记录中序序列 i n o r d e r inorder inorder v a l val val所对应的 i n d e x index index
  2. 当在中序序列中找到根节点后,被分为了三部分 [ 左子树 ] [左子树] [左子树], 根节点 根节点 根节点, [ 右子树 ] [右子树] [右子树],其中左子树和右子树可以通过递归的方式继续构造。我们知道了 左子树 左子树 左子树 右子树 右子树 右子树中的节点数目,也就知道了子树对应的后序遍历对应的长度,因为一颗子树的后序遍历和中序遍历长度是相同的,我们将原问题拆分成了规模更小的子问题,递归解决。
  3. [ p l , p r ] [pl, pr] [pl,pr] [ i l , i r ] [il, ir] [il,ir]分别表示后序遍历和中序遍历的区间范围,它们的初始值 p l = i l = 0 pl=il=0 pl=il=0 p r = i r = n − 1 pr=ir=n-1 pr=ir=n1。当我们找到根节点后其对应左子树的中序遍历区间为: [ i l , i n e d x − 1 ] [il, inedx-1] [il,inedx1],即左子树的长度为 i n d e x − 1 − i l index - 1 - il index1il,右子树的中序遍历区间为: [ i n d e x + 1 , i r ] [index + 1, ir] [index+1,ir]
  4. 左子树对应的后序序列区间: [ p l , p l + i n d e x − 1 − i l ] [pl, pl + index - 1 -il] [pl,pl+index1il] p r pr pr为根节点,左子树的根节点需要前进一位,长度为中序遍历得到的左子树长度 i n d e x − 1 − i l index -1-il index1il。右子树对应的后序序列区间: [ p l + i n d e x − i l , p r − 1 ] [pl+index-il, pr - 1] [pl+indexil,pr1],去掉左子树和根的剩余部分即为右子树的区间。
  5. 递归边界条件:当区间不存在时没有子树,即 p l > p r pl>pr pl>pr时返回 ∅ \emptyset

Code


/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int n = inorder.size();
        map<int, int> m;
        for(int i = 0; i < n; i++){
            m[inorder[i]] = i;
        }
        function<TreeNode*(int, int, int, int)> dfs = [&](int pl, int pr, int il, int ir) -> TreeNode*{
            if(il > ir) return nullptr;
            TreeNode* root = new TreeNode(postorder[pr]);
            int index = m[postorder[pr]];
            root->left = dfs(pl, pl + index - 1 - il, il, index - 1);
            root->right = dfs(pl + index - il, pr - 1, index + 1, ir);
            return root;
        };
        return dfs(0, n - 1, 0, n - 1);
    }
};

复杂度

  • 时间复杂度:
    O ( n ) O(n) O(n),其中n是节点的个数

  • 空间复杂度:
    O ( n ) O(n) O(n)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杭瑞文_hrw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值