前序遍历的顺序是:root -> left -> right
中序遍历的顺序是: left -> root -> right
前序遍历的第一个元素,必定是根节点。在中心遍历中,root前面的必定是左子树,root后面的必定是右子树。
1. 在前序遍历中,找到根节点,即pre[0],初始化前序、中序遍历数组中数据的范围preStart, preEnd, inStart, inEnd
2. 在中序遍历中,找到根节点的位置,rootIndexInVin
3. 那么按照刚刚的原理,我们就可以分别把pre和vin按照数据的长度、左子树的位置确定新的preStart, preEnd, inStart, inEnd
根据root的位置,inStart, inEnd我们可以确定,inStart~rootIndexInVin - 1属于左子树,可以确定左子树的inStart, inEnd
同样的,也可以根据inStart, inEnd我们可以确定,rootIndexInVin + 1 ~ inEnd属于右子树,可以确定右子树的inStart, inEnd
因而,我们计算出,左子树的长度,右子树的长度:
4. 根据左子树和右子树的长度,以及preStart, preEnd计算左右子树在前序遍历中的范围。
我们知道,前序遍历中第一个元素是根节点,因而,从preStart + 1开始,持续len(L)个元素都是左子树,因此,我们可以确认范围
preStart' = preStart + 1
preEnd' = preStart' + len(L) - 1 = (preStart + 1) + leftNodeLength - 1
在左子树范围的基础上,再延后len(R)个元素就是右子树范围
preStart" = preEnd' + 1 = (preStart + 1 + leftNodeLength - 1) + 1
preEnd" = preStart" + len(R) - 1 = (preStart + 1 + leftNodeLength - 1 + 1) + rightNodeLength - 1
好了这样,递归的完成二叉树的重建,直到所有的元素都遍历一遍。
import java.util.*;
/**
* Definition for binary tree
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {
return construct(pre, 0, pre.length - 1, vin, 0, vin.length - 1);
}
private TreeNode construct(int[] pre, int preStart, int preEnd, int[] vin, int inStart, int inEnd){
if (pre == null || pre.length == 0 || vin == null || vin.length == 0){
return null;
}
if (preStart > preEnd || inStart > inEnd){
return null;
}
// 前序遍历的第一个元素就是当前的根节点
int rootVal = pre[preStart];
// 找到在中序遍历的数组中,根节点的位置
int rootIndexInVin = inStart;
while (rootIndexInVin <= inEnd && vin[rootIndexInVin] != rootVal){
rootIndexInVin++;
}
// 根节点的左子树节点总共有:inStart~rootIndexInVin-1
int leftNodeLength = rootIndexInVin - inStart;
int rightNodeLength = inEnd - rootIndexInVin;
TreeNode rootNode = new TreeNode(rootVal);
rootNode.left = construct(pre, preStart + 1, (preStart + 1) + leftNodeLength - 1, vin, inStart, rootIndexInVin - 1);
rootNode.right = construct(pre, (preStart + 1 + leftNodeLength - 1) + 1, (preStart + 1 + leftNodeLength - 1) + 1 + rightNodeLength - 1, vin, rootIndexInVin + 1, inEnd);
return rootNode;
}
}