全栈开发知识库

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

题目

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

示例 1:

Image

  • 输入: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 保证是树的后序遍历

思路

  • 中序遍历(左 --> 根 --> 右)
  • 后序遍历(左 --> 右 --> 根)

核心规律:

  • 后序遍历的最后一个元素一定是当前树的根节点。
  • 找到根节点后,去中序遍历里找它的位置,根节点左边的全是左子树,右边的全是右子树。
  • 知道了左子树有多少个节点(leftSize),就能在后序遍历里切出左右子树的范围。除了左子树的个数和最后一个根,剩余中间的就是右子树。这样就可以又继续递归。

class TreeNode(var `val`: Int) {
    var left: TreeNode? = null
    var right: TreeNode? = null
}

class Solution {
    fun buildTree(inorder: IntArray, postorder: IntArray): TreeNode? {
        // 用 HashMap 预存中序每个值的下标,避免每次都线性查找
        var inMap = HashMap<Int, Int>()
        for (i in inorder.indices) {
            inMap[inorder[i]] = i
        }
        return build(inorder, postorder, 0, inorder.size - 1, 0, postorder.size - 1, inMap)
    }

    private fun build(
        inorder: IntArray,
        postorder: IntArray,
        inLeft: Int, inRight: Int,       // 当前子树在中序中的范围
        postLeft: Int, postRight: Int,   // 当前子树在后序中的范围
        inMap: HashMap<Int, Int>
    ): TreeNode? {
        // 递归终止条件:区间为空
        if (inLeft > inRight) return null

        // 后序最后一个元素是根节点
        var rootVal = postorder[postRight]
        var root = TreeNode(rootVal)

        // 在中序中找根节点的位置
        var inRootIndex = inMap[rootVal]!!

        // 左子树的节点数量
        var leftSize = inRootIndex - inLeft

        // 递归构建左子树
        root.left = build(
            inorder, postorder,
            inLeft, inRootIndex - 1,
            postLeft, postLeft + leftSize - 1,
            inMap
        )

        // 递归构建右子树
        root.right = build(
            inorder, postorder,
            inRootIndex + 1, inRight,
            postLeft + leftSize, postRight - 1,
            inMap
        )

        return root
    }
}

复杂度

  • 时间复杂度: O(n):每个节点只处理一次,HashMap 查找是 O(1)
  • 空间复杂度: O(n):HashMap 存储 n 个元素,递归栈最深 O(n)


  • 邮箱 :charon.chui@gmail.com
  • Good Luck!
本页由 Markdown 自动渲染 · 共 628 篇笔记