Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、题目 leetcode 从中序与后序遍历序列构造二叉树
给定两个整数数组 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 保证是树的后序遍历
二、题解
1.解读 要从中序与后序遍历序列构造二叉树就得先理解中序与后序遍历的规则:中序遍历的顺序是先遍历左子树的节点,然后是根节点,最后再到右子树的节点,对于其任意子树也是如此;后续遍历的顺序是先遍历左子树的节点,然后是右子树的节点,最后再到根节点,对于其任意的子树也是如此。
方法一
那么根据中序与后序遍历的顺序,可以知道后序遍历的最后一个节点必定是根节点,知道了根节点那么就可以再找出左右子树的节点了,左子树的根节点就是左节点,右子树的节点就是右节点,我们将后序遍历的这个根节点去中序遍历中查询根节点位置,找到这个根节点之后,其之前的节点就是左子树节点,其之后的节点就是右子树节点;那么再将左右子树的节点对应到后序遍历中,那么我们又获取到子树的中序与后序遍历的结果了,然后再重复寻找根节点的操作,最后就可以构造出整个二叉树了。具体的为了更快速的在中序遍历中寻找根节点,我们首先使用一个哈希表indexMap存储中序遍历数组inorder内元素节点与其下标索引的对应关系,这样我们就可以达到O(1)的时间查询根节点的下标。然后我们就递归的构造二叉树节点buildTree(inorder, postorder, inoLeft, inoRight, posLeft, posRight),具体的inorder、postorder分别代码中序遍历与后序遍历的结果数组,inoLeft、inoRight就代表inorder数组中当前树的中序遍历的结果数组的两个边界,初始的等于inorder数组边界;同理posLeft、posRight就代表postorder数组中当前树的后序遍历的结果数组的两个边界,初始的等于postorder数组边界。我们取后序遍历的最后一个元素节点postorder[posRight]来构造出当前树的根节点,然后在indexMap哈希表查询出该根节点的下标索引rootIndex,那么根据中序遍历的rootIndex根节点下标可以分割出[inoLeft, rootIndex - 1]为当前树的左子树节点的中序遍历结果数组,[rootIndex + 1, inoRight]为当前树的右子树节点的中序遍历结果数组。那么arrLen = rootIndex - inoLeft就是当前树的左子树的节点数量,那么对应到后序遍历的[posLeft, posLeft + arrLen - 1]就是当前树的左子树的后序遍历结果数组,[posLeft + arrLen, posRight - 1]就是当前树的右子树的后序遍历结果数组。对此我们就可以用分割出的子树的中序与后序遍历结果数组去递归的构造当前树的左右子树了。
三、代码
方法一 Java代码
class Solution {
private Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
public TreeNode buildTree(int[] inorder, int[] postorder) {
int len = inorder.length;
for (int i = 0; i < len; i++) {
indexMap.put(inorder[i], i);
}
return buildTree(inorder, postorder, 0, len - 1, 0, len - 1);
}
public TreeNode buildTree(int[] inorder, int[] postorder, int inoLeft, int inoRight, int posLeft, int posRight) {
if (posLeft > posRight) {
return null;
}
int rootIndex = indexMap.get(postorder[posRight]);
TreeNode root = new TreeNode(postorder[posRight]);
int arrLen = rootIndex - inoLeft;
root.left = buildTree(inorder, postorder, inoLeft, rootIndex - 1, posLeft, posLeft + arrLen - 1);
root.right = buildTree(inorder, postorder, rootIndex + 1, inoRight, posLeft + arrLen, posRight - 1);
return root;
}
}
时间复杂度:O(n),递归的遍历两个数组元素来构造二叉树,两个数组的元素都遍历了一次。
空间复杂度:O(n),需要一个哈希表存储中序遍历的元素节点与下标的对应关系,以及递归的栈空间。
四、总结 关键是找出根节点,找出了根节点,那么就可以找出左子树和右子树分别对应的中序与后序遍历结果了。