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

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

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

题目

给定两个整数数组 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、后序遍历的区间是怎样选的,(规则一!规则一!规则一!!!


版权声明:本文为weixin_46535567原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。