需求:
给定两个整数数组 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]
思路:
首先回忆一下如何根据两个顺序构造一个唯一的二叉树,相信理论知识大家应该都清楚,就是以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来再切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
如果让我们肉眼看两个序列,画一棵二叉树的话,应该分分钟都可以画出来。
流程如图:
那么代码应该怎么写呢?
说到一层一层切割,就应该想到了递归。
来看一下一共分几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
/**
* 二叉树 106. 从中序与后序遍历序列构造二叉树
* <p>
* 注意:两个输入数组一定是合法数组
* <p>
* 1.后序数组为0,空节点
* 2.后续数组最后一个元素为节点元素
* 3.寻找中序数组位置作为切割点
* 4.切割中序数组
* 5.切割后序数组
* 6.递归处理左区间 右区间
*/
public class BuildTree {
public TreeNode buildTree(int[] inorder, int[] postorder) {
// 后续数组为null 说明无元素,返回 null
if (postorder == null || postorder.length == 0) return null;
int rootVal = postorder[postorder.length - 1];
// 后续数组最后一位一定是中节点
TreeNode root = new TreeNode(rootVal);
if (postorder.length == 1) return root;
// 切割中序数组
int index = 0;
for (int i = 0; i < inorder.length; i++) {
if (inorder[i] == rootVal) index = i;
}
// 使用后序数组的中节点,切割中序数组
int[] leftInorder = Arrays.copyOf(inorder, index);
int rightLengt = inorder.length - index - 1;
int[] rightInorder = new int[rightLengt];
// 原数组 原数组起始位置 目标数组 目标数组起始位置 长度
System.arraycopy(inorder, index + 1, rightInorder, 0, rightLengt);
// 使用中序切割后的左子树数组切割后序数组;
int[] leftPostorder = Arrays.copyOf(postorder, leftInorder.length);
int[] rightPostorder = new int[postorder.length - leftInorder.length - 1];
System.arraycopy(postorder, leftInorder.length, rightPostorder, 0, postorder.length - leftInorder.length - 1);
// 左子树中序数组,左子树后续数组
root.left = buildTree(leftInorder, leftPostorder);// 左
// 右子树中序数组,右子树后续数组
root.right = buildTree(rightInorder, rightPostorder);// 右
return root;
}
}