LeetCode 106.Construct Binary Tree from Inorder and Postorder Traversal(用中序与后序遍历构造一棵二叉树) 解题分析

题目来源

https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/

题目描述

Given inorder and postorder traversal of a tree, construct the binary tree.

Note:

You may assume that duplicates do not exist in the tree.

For example, given

inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]

Return the following binary tree:

LeetCode 106.Construct Binary Tree from Inorder and Postorder Traversal(用中序与后序遍历构造一棵二叉树) 解题分析

题意分析

给出一棵二叉树的中序遍历数组和后序遍历数组,还原这课二叉树。

前序知识

相信能看到这篇博客的你们一定已经知道二叉树、中序遍历和后序遍历(当然还有先序遍历)是什么。

假设我们有如下一棵二叉树:
LeetCode 106.Construct Binary Tree from Inorder and Postorder Traversal(用中序与后序遍历构造一棵二叉树) 解题分析

它的中序遍历数组数是 [4,2,5,1,6,3,7],它的后序遍历数组数是 [4,5,2,6,7,3,1]

经过观察,我们应该能发现:

  1. 中序遍历数组的根结点元素“1”的左边的数组([4,2,5])是根结点左子树的中序遍历数组,右边的数组([6,3,7])是根结点右子树的中序遍历数组。
  2. 后序遍历数组的最后那个元素是根结点元素“1”,左子树数组是除最后一个元素(根结点)外靠前的部分([4,5,2]),右子树数组是靠后的那部分([6,7,3])。

于是我们可以总结:

  1. 中序遍历数组的结构是:若一个数组表示一个二叉树,那么数组中有一个元素是根结点,在根节点的左边的数组是左子树数组,在根结点右边的数组是右子树数组。这个根结点元素在哪?需要有额外信息确定,比如后序遍历数组的最后一个元素(或者先序遍历的第一个元素)。
  2. 后序遍历数组的结构是:若一个数组表示一棵二叉树,那么最后一个元素是根结点,左子树数组是除最后一个元素(根结点)外靠前的部分,右子树数组是靠后的那部分。

题目思路

所以本题的思路可以是:用后序遍历数组的最后一个元素确定二叉树的根结点元素root_val,然后使用这个元素找到它在中序遍历数组的位置inindex,(中序遍历数组下标从instartinend)从而确定左右子树的中序遍历数组;同时利用左右子树中序遍历数组的长度确定左右子树后序遍历数组,最后将问题划分成“找左右子数组的根结点”的递归问题。

加粗部分要怎么做呢?右子树长度是inend-inindex,那么后序遍历数组(后序遍历数组最后一个元素的下标是postend)的右子树的最后一个元素的下标是postend-1,左子树的最后一个元素下标是postend-1-(inend-instart)

对于后序遍历数组,我们这需要知道它的结束部分postend。因为结束部分是它所在子树数组的根结点,而它的poststart并没有什么卵用。

做递归还需要有终止条件,认为instart>inend就是终止条件。

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return helper(inorder, postorder, 0, inorder.size()-1, postorder.size()-1);
    }
    TreeNode* helper(vector<int> &inorder, vector<int> &postorder, int instart, int inend, int postend) {
        if(instart>inend) {  //终止条件
            return NULL;
        }
        int root_val = postorder[postend];  //从后序遍历数组的最后一个元素获得当前树的根结点
        int inindex;
        for(int i=instart; i<=inend; i++) {  //相应得到中序遍历数组中根结点位置
            if(root_val == inorder[i]) {
                inindex = i;
            }
        }
        TreeNode* right = helper(inorder, postorder, inindex+1, inend, postend-1);  // 构建右子树
        TreeNode* left = helper(inorder, postorder, instart, inindex-1, postend-1-(inend-inindex));  // 构建左子树
        TreeNode* root = new TreeNode(root_val);
        root->left = left;
        root->right = right;
        return root; //返回构建好的树
    }
};

你的赞或关注都是对博主莫大的激励!