Construct Binary Tree From In-order and Post-order Traversal

2018, Aug 26    

问题描述

通过二叉树的中序和后序遍历结果,构造这棵二叉树。

注意: 树中不存在值重复的节点。

例如,给出如下中序和后序遍历结果:

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

构造出以下二叉树:

    3
   / \
  9  20
    /  \
   15   7

解决思路

二叉树的后续遍历是按照“左-右-根”的顺序访问树中的所有节点的,因此后续遍历结果的最后一个值必然是整棵树的根结点,以后续遍历 postorder = [9,15,7,20,3] 为例,3 就是整棵树的根结点了。而二叉树的中序遍历是按照“左-根-右”的顺序访问树中的所有节点的,所以根在中序遍历结果的中间。

我们可以根据后续遍历得到的根节点,将中序遍历的结果分成左子树和右子树。以中序遍历 inorder = [9,3,15,20,7] 为例,由于之前通过后续遍历知道了 3 是根节点,因此左子树是一棵只包含了 9 一个节点的树,而右子树则是一棵包含了 15、20、7 三个节点的树。

是不是又联想到递归了?没错,我们可以将构建整棵树的任务分解成构建左子树和右子树两个任务,左子树的构建又可以分解成构建“左左子树”和“左右子树”两个任务,右子树的构建同样地又可以分解成构建“右左子树”和“右右子树”两个任务,如此往复。

最后,给出我的代码如下:

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) {
            return NULL;
        }
        // The last element of postorder is the value of the root
        int rootVal = *(postorder.end() - 1);
        TreeNode *root = new TreeNode(rootVal);
        
        // Locate the middle of inorder
        vector<int>::iterator mid = std::find(inorder.begin(), inorder.end(), rootVal);
        // if (mid == inorder.begin()) {
        //     return root;
        // }
        
        // Try to build left Tree recursively
        vector<int> leftInOrder(inorder.begin(), mid);
        vector<int> leftPostOrder(postorder.begin(), postorder.begin() + (mid - inorder.begin()));
        root->left = buildTree(leftInOrder, leftPostOrder);
        
        // Try to build right Tree recursively
        vector<int> rightInOrder(mid + 1, inorder.end());
        vector<int> rightPostOrder(postorder.begin() + (mid - inorder.begin()), postorder.end() - 1);
        root->right = buildTree(rightInOrder, rightPostOrder);
        return root;
    }
};

可惜的是,这一份代码的运行效率并不高(仅仅击败了 15% 的 C++ 提交),我想可能是每一次递归都初始化了很多 vector<int> 类型,浪费了很多时间,可以考虑优化一下。