106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 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
保证是树的后序遍历
思路
- 如果数组为空,则说明是空节点
- 数组不为空,从后序数组中找到最后一个元素作为节点元素
- 找到后序遍历的最后一个元素在中序数组的位置,记作切割点
- 以切割点划分中序数组,分成左右子树数组
- 切割后序数组
- 递归处理后序左右分割的数组
Java实现代码
public TreeNode reverse(int[] inorder, int[] postorder) {
//1. 如果数组为空,则说明是空节点
if (inorder.length == 0) {
return null;
}
//2. 数组不为空,从后序数组中找到最后一个元素作为节点元素
TreeNode root = new TreeNode(postorder[postorder.length-1]);
int delimiterIndex;
//3. 找到后序遍历的最后一个元素在中序数组的位置,记作切割点
for (delimiterIndex = 0; delimiterIndex < inorder.length; delimiterIndex++) {
if (inorder[delimiterIndex] == root.val){
break;
}
}
//4. 以切割点划分中序数组,分成左右子树数组
int[] leftInOrder = Arrays.copyOfRange(inorder,0,delimiterIndex);
int[] rightInOrder = Arrays.copyOfRange(inorder,delimiterIndex+1,inorder.length);
//5. 切割后序数组
int[] leftPostOrder = Arrays.copyOfRange(postorder, 0, delimiterIndex);
int[] rightPostOrder = Arrays.copyOfRange(postorder, delimiterIndex, postorder.length - 1);
//6. 递归处理后序左右分割的数组
root.left = reverse(leftInOrder,leftPostOrder);
root.right = reverse(rightInOrder,rightPostOrder);
return root;
}
改进
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
return reverse(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode reverse(int[] inorder, int inOrderBegin, int inOrderEnd, int[] postorder, int postOrderBegin, int postOrderEnd) {
//1. 如果数组为空,则说明是空节点
if (postOrderEnd == postOrderBegin) {
return null;
}
//2. 数组不为空,从后序数组中找到最后一个元素作为节点元素
TreeNode root = new TreeNode(postorder[postOrderEnd - 1]);
if (postOrderEnd - postOrderBegin == 1) return root;
int delimiterIndex;
//3. 找到后序遍历的最后一个元素在中序数组的位置,记作切割点
for (delimiterIndex = inOrderBegin; delimiterIndex < inOrderEnd; delimiterIndex++) {
if (inorder[delimiterIndex] == root.val){
break;
}
}
//4. 以切割点划分中序数组,分成左右子树数组
int leftInOrderBegin = inOrderBegin;
int leftInOrderEnd = delimiterIndex;
int rightInOrderBegin = delimiterIndex + 1;
int rightInOrderEnd = inOrderEnd;
//5. 切割后序数组
int leftPostOrderBegin = postOrderBegin;
int leftPostOrderEnd = postOrderBegin + delimiterIndex - inOrderBegin;
int rightPostOrderBegin = postOrderBegin + delimiterIndex - inOrderBegin;
int rightPostOrderEnd = postOrderEnd - 1;
//6. 递归处理后序左右分割的数组
root.left = reverse(inorder,leftInOrderBegin,leftInOrderEnd,postorder,leftPostOrderBegin,leftPostOrderEnd);
root.right = reverse(inorder,rightInOrderBegin,rightInOrderEnd,postorder,rightPostOrderBegin,rightPostOrderEnd);
return root;
}
}