106. 从中序与后序遍历序列构造二叉树
难度中等437
根据一棵树的中序遍历与后序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
在递归方法中,传入子数组的边界下标
注意:在递归方法中,有一个数组的边界下标。
计算的依据是递归方法传入的 中序遍历数组(的子数组)和后序遍历数组(的子数组)的长度相等。我的办法
是解方程计算未知数,具体需要计算哪个参数我在下面的代码中已经注明了。
下面展示了一个计算边界的方法。
public class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
int inLen = inorder.length;
int postLen = postorder.length;
// 特判
if (inLen != postLen) {
throw new RuntimeException("输入错误");
}
return buildTree(inorder, 0, inLen - 1, postorder, 0, postLen - 1);
}
/**
* 使用中序遍历序列 inorder 的子区间 [inLeft, inRight]
* 与后序遍历序列 postorder 的子区间 [postLeft, postRight] 构建二叉树
*
* @param inorder 中序遍历序列
* @param inLeft 中序遍历序列的左边界
* @param inRight 中序遍历序列的右边界
* @param postorder 后序遍历序列
* @param postLeft 后序遍历序列的左边界
* @param postRight 后序遍历序列的右边界
* @return 二叉树的根结点
*/
private TreeNode buildTree(int[] inorder, int inLeft, int inRight,
int[] postorder, int postLeft, int postRight) {
if (inLeft > inRight || postLeft > postRight) {
return null;
}
int pivot = postorder[postRight];
int pivotIndex = inLeft;
// 注意这里如果编写不当,有数组下标越界的风险
while (inorder[pivotIndex] != pivot) {
pivotIndex++;
}
TreeNode root = new TreeNode(pivot);
root.left = buildTree(inorder, inLeft, pivotIndex - 1,
postorder, postLeft, postRight - inRight + pivotIndex - 1);
root.right = buildTree(inorder, pivotIndex + 1, inRight,
postorder, postRight - inRight + pivotIndex, postRight - 1);
return root;
}
}
可以在递归构造前,把中序遍历的值和下标放在哈希表中,就不需要通过遍历得到当前根结点在中序遍历中的位置了。
import java.util.HashMap;
import java.util.Map;
public class LEE106 {
private int[] postorder;
private Map<Integer, Integer> hash;
public TreeNode buildTree(int[] inorder, int[] postorder) {
int inLen = inorder.length;
int poseLen = postorder.length;
if (inLen == poseLen) {
return null;
}
this.postorder = postorder;
this.hash = new HashMap<>();
for (int i = 0; i < inLen; i++) {
hash.put(inorder[i], i);
}
return buildTree1(0, inLen - 1, 0, poseLen - 1);
}
/**
* 使用中序遍历序列 inorder 的子区间 [inLeft, inRight]
* 与后序遍历序列 postorder 的子区间 [postLeft, postRight] 构建二叉树
*
* @param inLeft 中序遍历序列的左边界
* @param inRight 中序遍历序列的右边界
* @param postLeft 后序遍历序列的左边界
* @param postRight 后序遍历序列的右边界
* @return 二叉树的根结点
*/
private TreeNode buildTree1(int inLeft, int inRight, int postLeft, int postRight) {
if (inLeft > inRight || postLeft > postRight) {
return null;
}
int pivot = postorder[postRight];
int pivotIndex = hash.get(pivot);
TreeNode root = new TreeNode(pivot);
root.left = buildTree1(inLeft, pivotIndex - 1, postLeft, postRight - inRight + pivotIndex - 1);
root.right = buildTree1(pivotIndex + 1, inRight, postRight - inRight + pivotIndex, postRight - 1);
return root;
}
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
}