73.从中序与后序遍历序列构造二叉树
题目
给定两个整数数组 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 保证是树的后序遍历
思路
- 中序遍历(左 --> 根 --> 右)
- 后序遍历(左 --> 右 --> 根)
核心规律:
- 后序遍历的最后一个元素一定是当前树的根节点。
- 找到根节点后,去中序遍历里找它的位置,根节点左边的全是左子树,右边的全是右子树。
- 知道了左子树有多少个节点(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!