思路:在前序序列中,根结点是第一个元素。在中序序列中找到它就可以将左右子树区分开。然后就可以重建二叉树
分析:
左子树的结点个数numLeft = k - inL
左子树中序序列[inL, k - 1],后序序列 [postL, postL + numLeft - 1]。
右子树中序序列[k + 1, inR],后序序列 [postL + numLeft, postR - 1]。
后记:类似还有已知道中序序列和先序序列,思路很相似。
仍然是左子树的结点个数numLeft = k - inL
左子树中序序列[inL, k - 1],先序序列 [preL + 1, preL + numLeft]。
右子树中序序列[k + 1, inR],先序序列 [preL + numLeft + 1, preR]。
class Solution{
public TreeNode buildTree(int[] preorder, int[] inorder){
return BuildTree(0, 0, inorder.length - 1, preorder, inorder);
}
public TreeNode BuildTree(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder){
// preStart > preorder.length - 1 这个条件可以不要
if (preStart > preorder.length - 1 || inStart > inEnd){
return null;
}
// 新建根节点 根节点的值初始化为 preorder[preStart]
TreeNode root = new TreeNode(preorder[preStart]);
// 在中序序列中找到根节点的索引
int index = 0;
for (int i = inStart; i <= inEnd; i++) {
if (inorder[i] == root.val){
index = i;
break;
}
}
// 左子树结点个数
int numLeft = index - inStart;
root.left = BuildTree(preStart + 1, inStart, index - 1, preorder, inorder);
root.right = BuildTree(preStart + 1 + numLeft, index + 1, inEnd, preorder, inorder);
return root;
}
}
class Solution {
int[] preorder;
HashMap<Integer, Integer> dic = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder){
this.preorder = preorder;
// 中序数组的 值->索引 的映射, 方便在中序数组中找到根节点(以空间换时间)
for(int i = 0; i < inorder.length; i++)
dic.put(inorder[i], i);
return BuildTree(0, 0, inorder.length - 1);
}
TreeNode BuildTree(int pre_root, int in_left, int in_right){
if (in_left > in_right) return null;
// 新建根节点 根节点的值初始化为 preorder[preStart]
TreeNode node = new TreeNode(preorder[pre_root]);
// 在中序序列中找到根节点的索引
int index = dic.get(preorder[pre_root]);
// 左子树节点的个数
int num_left = index - in_left;
//左子树在先序数组中的索引为pre_root + 1, 左子树在中序数组的索引是[in_left,index-1]
node.left = BuildTree(pre_root + 1, in_left, index - 1);
//右子树在先序数组中的索引为pre_root + 1 + 左子树个数num_left,右子树在中序数组的索引是[index+1,in_right]
node.right = BuildTree(pre_root + 1 + num_left, index + 1, in_right);
return node;
}
}
import java.util.HashMap;
import java.util.Map;
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public class Solution {
// 使用全局变量是为了让递归方法少传一些参数,不一定非要这么做
private Map<Integer, Integer> reverses;
private int[] preorder;
public TreeNode buildTree(int[] preorder, int[] inorder) {
int preLen = preorder.length;
int inLen = inorder.length;
// 可以不做判断,因为题目中给出的数据都是有效的
if (preLen != inLen) {
return null;
}
this.preorder = preorder;
// 以空间换时间,否则,找根结点在中序遍历中的位置需要遍历
reverses = new HashMap<>(inLen);
for (int i = 0; i < inLen; i++) {
reverses.put(inorder[i], i);
}
return buildTree(0, preLen - 1, 0, inLen - 1);
}
/**
* 根据前序遍历数组的 [preL, preR] 和 中序遍历数组的 [inL, inR] 重新组建二叉树
*
* @param preL 前序遍历数组的区间左端点
* @param preR 前序遍历数组的区间右端点
* @param inL 中序遍历数组的区间左端点
* @param inR 中序遍历数组的区间右端点
* @return 构建的新二叉树的根结点
*/
private TreeNode buildTree(int preL, int preR,
int inL, int inR) {
if (preL > preR || inL > inR) {
return null;
}
// 构建的新二叉树的根结点一定是前序遍历数组的第 1 个元素
int pivot = preorder[preL];
TreeNode root = new TreeNode(pivot);
int pivotIndex = reverses.get(pivot);
// 这一步得画草稿,计算边界的取值,必要时需要解方程,并不难
root.left = buildTree(preL + 1, preL + (pivotIndex - inL), inL, pivotIndex - 1);
root.right = buildTree(preL + (pivotIndex - inL) + 1, preR, pivotIndex + 1, inR);
return root;
}
}