跳转至

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

力扣链接(中等):https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal

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

示例 1:

img

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

示例 2:

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

提示:

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

个人题解

C++
/**
 * 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* traversal(vector<int>& inorder, int iBegin, int iEnd, vector<int>& postorder, int pBegin, int pEnd) {
        // 每次从后序遍历查找中节点,在这之前需要判断后序遍历是否还有值
        if(pBegin == pEnd) return NULL;

        // 建立中节点
        int rootValue = postorder[pEnd - 1];
        auto root = new TreeNode(rootValue);

        // 分割中序遍历,统一使用左闭右开
        int index;
        for(index = iBegin; index < iEnd; index++) {
            if(inorder[index] == rootValue) break;
        }
        // 中序遍历分割左子树区间
        int leftIBegin = iBegin;
        int leftIEnd = index; // 右边是开,所以这里并不包含 inorder[index]
        // 右子树区间
        int rightIBegin = leftIEnd + 1;
        int rightIEnd = iEnd;

        // 统一使用左闭右开
        // 分割后序遍历,只需要根据中序遍历分割出的左子树长度和右子树长度来切割即可
        int leftPBegin = pBegin;
        int leftPEnd = leftPBegin + (leftIEnd - leftIBegin);

        int rightPBegin = leftPEnd;
        // 因为是右开区间,所以已经自动去掉末尾的中节点
        int rightPEnd = rightPBegin + (rightIEnd - rightIBegin); 

        // 递归子树
        root->left = traversal(inorder, leftIBegin, leftIEnd, postorder, leftPBegin, leftPEnd);
        root->right = traversal(inorder, rightIBegin, rightIEnd, postorder, rightPBegin, rightPEnd);

        return root;
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(!inorder.size() || !postorder.size()) return NULL;
        // 左闭右开
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};