二叉树——从中序与后序遍历序列构造二叉树

从中序与后序遍历序列构造二叉树

基础首先要掌握二叉树的前序、中序、后续遍历,理解递归在二叉树操作中的重要地位,熟悉分治法在解决实际问题中的广泛应用。

题目

给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:


输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

提示:

1 <= inorder.length <= 3000
postorder.length == inorder.length
-3000 <= inorder[i], postorder[i] <= 3000
inorder 和 postorder 都由 不同 的值组成
postorder 中每一个值都在 inorder 中
inorder 保证是树的中序遍历
postorder 保证是树的后序遍历

作者:力扣 (LeetCode)
链接:https://leetcode-cn.com/leetbook/read/data-structure-binary-tree/xo98qt/
来源:力扣(LeetCode)

题目理解

给定一个二叉树,
在这里插入图片描述

前序遍历是

[2,3,5,6,4,7,8]

中序遍历是

[5,3,6,2,7,4,8]

后序遍历是

[5,6,3,7,8,4,2]

首先,我们根据遍历的规则可以知道:
1、中序遍历的某个数字的左边全都在他的左子树,且左子树的数据在后序遍历中仍旧处于相同长度的连续区域中;右边全在他的右子树且右子树的数据在后序遍历中仍旧处于相同长度的连续区域中;
2、一个树的后序遍历的最后一个是根节点;

important:
inorder:中序遍历数组;head1:中序遍历选取区间起始值下标;tail1:中序遍历选取区间结束值下标;
postorder:后序遍历数组;head2:后序遍历选取区间起始值下标;tail2:后序遍历选取区间结束值下标;

我们定义一个函数func,他的作用是:建立区间元素(中序遍历和后序遍历两个区间)所代表的树
1、特判:结束递归的条件是选取区间不合理(即区间起始值head大于结束值tail),返回一个NULL;或区间中只含一个元素,那它即使树的根节点,也是叶子节点,此时返回节点值为该区间元素的值的节点即可结束递归;
2、根据后序遍历获得根节点 postorder[tail2] 的值 nodeval;
3、求该树的左子树和右子树;
(对区间选取的变化!!depend on val)。
在中序遍历中找到val的位置下标 idx,根据规则得到;

  • 左子树中序遍历起始值:head1;中序遍历结束值:idx - 1; 后序遍历起始值:head2;后序遍历结束值:idx- 1;
  • 右子树中序遍历起始值:idx + 1;中序遍历结束值:tail1;后序遍历起始值:idx;后序遍历结束值:tail - 1;
    (后序遍历区间选择记住规则一描述的

代码实现

/**
 * 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) {
        if(inorder.empty()) return nullptr;
        in_order=inorder;
        post_order = postorder;
        return func(0,inorder.size()-1,0,postorder.size()-1);
    }
private:
    vector<int> in_order,post_order;
    TreeNode* func(int head1,int tail1,int head2,int tail2){
        if(head1 > tail1) return nullptr;
        int nodeval = post_order[tail2];
        TreeNode* root = new TreeNode(nodeval);
        if(head1 == tail1) return root;
        int offset = 0;
        while(in_order[head1 + offset] != nodeval) offset++;

        root->left = func(head1,head1 + offset - 1,head2,head2+offset-1);
        root->right = func(head1+offset+1,tail1,head2+offset,tail2-1);
        return root;
    }
};

总结

一定要理解遍历规则,这里的重点是
1、能意识到中序遍历根节点的左子树都在左边,右边一样;
2、后序遍历的区间是怎样选的,(规则一!规则一!规则一!!!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

四库全书的酷

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

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

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

打赏作者

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

抵扣说明:

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

余额充值