public class Solution {
public int[] preorderTraversal (TreeNode root) {
//前序遍历 遵循根--->左--->右
//创建一个集合来存储遍历的结点值
List<Integer> list = new ArrayList<>();
helper(root, list);
int[] res = new int[list.size()];
for (int i = 0; i < res.length; i++) {
//将集合中的元素转存到数组中
res[i] = list.get(i);
}
//将数组返回
return res;
}
private void helper(TreeNode node, List<Integer> list) {
if (node == null) {
return;
}
//存入结点
list.add(node.val);
//遍历左树
helper(node.left, list);
//遍历右树
helper(node.right, list);
}
}
思路步骤:
什么是二叉树的中序遍历,简单来说就是“左根右”,展开来说就是对于一棵二叉树,我们优先访问它的左子树,等到左子树全部节点都访问完毕,再访问根节点,最后访问右子树。同时访问子树的时候,顺序也与访问整棵树相同。
可以理解为递归的子问题,根节点的左右子树访问方式与原本的树相同,可以看成一颗树进行中序遍历,因此可以用递归处理:
public class Solution {
public int[] inorderTraversal (TreeNode root) {
// write code here
/**
递归法
*/
//中序遍历 遵循左--->根--->右
//创建一个集合来存储遍历的结点值
List<Integer> list = new ArrayList<>();
helper(root, list);
int[] res = new int[list.size()];
for (int i = 0; i < res.length; i++) {
//将集合中的元素转存到数组中
res[i] = list.get(i);
}
//将数组返回
return res;
}
private void helper(TreeNode node, List<Integer> list) {
if (node == null) {
return;
}
//遍历左树
helper(node.left, list);
//存入结点
list.add(node.val);
//遍历右树
helper(node.right, list);
}
}
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return int整型一维数组
*/
public int[] postorderTraversal (TreeNode root) {
// write code here
//后序遍历 遵循左--->右--->根
//创建一个集合来存储遍历的结点值
List<Integer> list = new ArrayList<>();
helper(root, list);
int[] res = new int[list.size()];
for (int i = 0; i < res.length; i++) {
//将集合中的元素转存到数组中
res[i] = list.get(i);
}
//将数组返回
return res;
}
private void helper(TreeNode node, List<Integer> list) {
//basecase
if (node == null) {
return;
}
helper(node.left, list);
helper(node.right, list);
list.add(node.val);
}
}
BFS广度优先遍历
思路:
二叉树的层次遍历就是按照从上到下每行,然后每行中从左到右依次遍历,得到的二叉树的元素值。对于层次遍历,我们通常会使用队列
来辅助:
因为队列是一种先进先出的数据结构,我们依照它的性质,如果从左到右访问完一行节点,并在访问的时候依次把它们的子节点加入队列,那么它们的子节点也是从左到右的次序,且排在本行节点的后面,因此队列中出现的顺序正好也是从左到右,正好符合层次遍历的特点。
具体做法:
public class Solution {
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
//BFS 广度优先遍历
//通常与队列一起配合
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
//basecase
if (root == null) {
return res;
}
//定义一个队列
Queue<TreeNode> q = new LinkedList<>();
//将root 先丢到队列里
q.add(root);
//开启新的层
while (q.size() > 0) {
//维护一个size用来记录队列中元素的数量
//每次循环都更新size
int size = q.size();
//定义一个List用来记录二叉树的某一行
ArrayList<Integer> list = new ArrayList<>();
//当前层的元素
while (size > 0) {
//将队列中的元素取出来
TreeNode cur = q.poll();
//存到List
list.add(cur.val);
//判断取出的这个元素有没有左右孩子
if (cur.left != null) {
//将左孩子加到队列
q.add(cur.left);
}
if (cur.right != null) {
q.add(cur.right);
}
size--;
}
res.add(new ArrayList<>(list));
}
return res;
}
}
DFS深度优先遍历
思路:
既然二叉树的前序、中序、后序遍历都可以轻松用递归实现,树型结构本来就是递归喜欢的形式,那我们的层次遍历是不是也可以尝试用递归来试试呢?
按行遍历的关键是每一行的深度对应了它输出在二维数组中的深度,即深度可以与二维数组的下标对应,那我们可以在递归的访问每个节点的时候记录深度:
dfs(root, res, 0);
进入子节点则深度加1:
//递归左右时深度记得加1
dfs(node.left, res, level + 1);
dfs(node.right, res, level + 1);
每个节点值放入二维数组相应行。
res.get(level).add(node.val);
因此可以用递归实现:
具体做法:
public class Solution {
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
//DFS 深度优先遍历
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
//basecase
if (root == null) {
return res;
}
dfs(root, res, 0);
return res;
}
private void dfs(TreeNode node, ArrayList<ArrayList<Integer>> res, int level) {
//递归退出的条件
if (node == null) {
return;
}
//当前层级大于数组大小
if (level > res.size() - 1) {
//就需要加一个空的数组,才能存放元素
res.add(new ArrayList<>());
}
res.get(level).add(node.val);
if (node.left != null) {
dfs(node.left, res, level + 1);
}
if (node.right != null) {
dfs(node.right, res, level + 1);
}
}
}
思路:
按照层次遍历按层打印二叉树的方式,每层分开打印,然后对于每一层利用flag标记,第一层为false,之后每到一层取反一次,如果该层的flag为true,则记录的数组整个反转即可。
//奇数行反转,偶数行不反转
if(flag)
reverse(row.begin(), row.end());
但是难点在于如何每层分开存储,从哪里知晓分开的时机?在层次遍历的时候,我们通常会借助队列(queue),事实上,队列中的值大有玄机,让我们一起来看看:当根节点进入队列时,队列长度为1,第一层节点数也为1;若是根节点有两个子节点,push进队列后,队列长度为2,第二层节点数也为2;若是根节点一个子节点,push进队列后,队列长度为为1,第二层节点数也为1。由此,我们可知,每层的节点数等于进入该层时队列长度,因为刚进入该层时,这一层每个节点都会push进队列,而上一层的节点都出去了。
int n = temp.size();
for(int i = 0; i < n; i++){
//访问一层
}
具体做法:
public class Solution {
public ArrayList<ArrayList<Integer>> Print (TreeNode pRoot) {
// write code here
TreeNode head = pRoot;
ArrayList<ArrayList<Integer>> res = new ArrayList<ArrayList<Integer>>();
if(head == null){
//返回空list
return res;
}
//队列存储,进行层次遍历
Queue<TreeNode> temp = new LinkedList<TreeNode>();
//先把根节点加到队列里面
temp.offer(head);
//定义一个变量存放队列中取出来节点
TreeNode p;
//定义一个flag变量
boolean flag = true;
while(!temp.isEmpty()){
//定义一个数组记录二叉树的某一行
ArrayList<Integer> row = new ArrayList<>();
//维护一个变量记录队列元素的个数
int n = temp.size();
//奇数行反转,偶数行不反转
flag = !flag;
//因为首先进入的都是根节点,所以每层节点多少,队列大小就是多少
for(int i = 0; i < n; i++){
//将队列中的节点取出来
p = temp.poll();
//加到存放行的列表
row.add(p.val);
//若是左右孩子存在,则存入左右孩子作为下一个层次
if(p.left != null){
temp.offer(p.left);
}
if(p.right != null){
temp.offer(p.right);
}
}
//奇数行反转,偶数行不反转
if(flag){
Collections.reverse(row);
}
res.add(row);
}
return res;
}
}
方法一:递归
二叉树的递归,则是将某个节点的左子树、右子树看成一颗完整的树,那么对于子树的访问或者操作就是对于原树的访问或者操作的子问题,因此可以自我调用函数不断进入子树。
思路:
最大深度是所有叶子节点的深度的最大值,深度是指树的根节点到任一叶子节点路径上节点的数量,因此从根节点每次往下一层深度就会加1。因此二叉树的深度就等于根节点这个1层加上左子树和右子树深度的最大值,而每个子树我们都可以看成一个根节点,继续用上述方法求的深度,于是我们可以对这个问题划为子问题,利用递归来解决:
具体做法:
import java.util.*;
public class Solution {
public int maxDepth (TreeNode root) {
//空节点没有深度
if(root == null)
return 0;
//返回子树深度+1
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
}
方法二:队列
队列是一种仅支持在表尾进行插入操作、在表头进行删除操作的线性表,插入端称为队尾,删除端称为队首,因整体类似排队的队伍而得名。它满足先进先出的性质,元素入队即将新元素加在队列的尾,元素出队即将队首元素取出,它后一个作为新的队首。
思路:
既然是统计二叉树的最大深度,除了根据路径到达从根节点到达最远的叶子节点以外,我们还可以分层统计。对于一棵二叉树而言,必然是一层一层的,那一层就是一个深度,有的层可能会很多节点,有的层如根节点或者最远的叶子节点,只有一个节点,但是不管多少个节点,它们都是一层。因此我们可以使用层次遍历,二叉树的层次遍历就是从上到下按层遍历,每层从左到右,我们只要每层统计层数即是深度。
具体做法:
public class Solution {
public int maxDepth (TreeNode root) {
//BFS
// write code here
if (root == null) {
return 0;
}
//创建一个队列
Queue<TreeNode> q = new LinkedList<>();
//将根节点加入到队列
q.offer(root);
//维护一个res记录深度
int res = 0;
//如果这个队列不等于空
while (!q.isEmpty()) {
//每一层的个数
int size = q.size();
while (size-- > 0) {
//如果这一层的个数大于0,就取出来
TreeNode cur = q.poll();
//取出来之后看这个节点是否有左右孩子
if (cur.left != null)
//加入到队列
q.offer(cur.left);
if (cur.right != null)
q.offer(cur.right);
}
//每一层的个数++
res++;
}
return res;
}
}
思路步骤:
既然是检查从根到叶子有没有一条等于目标值的路径,那肯定需要从根节点遍历到叶子,我们可以在根节点每次往下一层的时候,将sum减去节点值,最后检查是否完整等于0. 而遍历的方法我们可以选取二叉树常用的递归前序遍历,因为每次进入一个子节点,更新sum值以后,相当于对子树查找有没有等于新目标值的路径,因此这就是子问题,递归的三段式为:
具体做法:
public class Solution {
public boolean hasPathSum (TreeNode root, int sum) {
// write code here
//如果根节点为空,或者叶子节点也遍历完了也没找到这样的结果,就返回false
if (root == null)
return false;
//如果到叶子节点了,并且剩余值等于叶子节点的值,说明找到了这样的结果,直接返回true
if (root.left == null && root.right == null && sum - root.val == 0)
return true;
//分别沿着左右子节点走下去,然后顺便把当前节点的值减掉,左右子节点只要有一个返回true,
//说明存在这样的结果
return hasPathSum(root.left, sum - root.val) ||
hasPathSum(root.right, sum - root.val);
}
}
思路:
二叉搜索树最左端的元素一定最小,最右端的元素一定最大,符合“左中右”的特性,因此二叉搜索树的中序遍历就是一个递增序列,我们只要对它中序遍历就可以组装称为递增双向链表。
具体做法:
public class Solution {
//返回的第一个指针,即为最小值,先定为null
TreeNode head = null;
//中序遍历当前值的上一位,初值为最小值,先定为null
TreeNode pre = null;
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree == null) {
return null;
}
//首先递归到最左最小值
Convert(pRootOfTree.left);
//找到最小值,然后初始化head和pre
if (pre == null) {
head = pRootOfTree;
pre = pRootOfTree;
}
//当前节点与上一节点建立连接,将pre设置为当前值
else {
pre.right = pRootOfTree;
pRootOfTree.left = pre;
pre = pRootOfTree;
}
Convert(pRootOfTree.right);
return head;
}
}
思路:
前序遍历的时候我们采用的是“根左右”的遍历次序,如果这棵二叉树是对称的,即相应的左右节点交换位置完全没有问题,那我们是不是可以尝试“根右左”遍历,按照轴对称图像的性质,这两种次序的遍历结果应该是一样的。
不同的方式遍历两次,将结果拿出来比较看起来是一种可行的方法,但也仅仅可行,太过于麻烦。我们不如在遍历的过程就结果比较了。而遍历方式依据前序递归可以使用递归:
具体做法:
public class Solution {
public boolean isSymmetrical (TreeNode pRoot) {
return recursion(pRoot, pRoot);
}
public boolean recursion(TreeNode root1, TreeNode root2) {
//可以两个都为空,
if (root1 == null && root2 == null) {
return true;
}
//只有一个为空或者节点值不同,一定不对称
if (root1 == null || root2 == null || root1.val != root2.val) {
return false;
}
//每层对应的节点进入递归比较
return recursion(root1.left, root2.right) && recursion(root1.right, root2.left);
}
}
思路:
要将一棵二叉树的节点与另一棵二叉树相加合并,肯定需要遍历两棵二叉树,那我们可以考虑同步遍历两棵二叉树,这样就可以将每次遍历到的值相加在一起。遍历的方式有多种,这里推荐前序递归遍历。
具体做法:
public class Solution {
public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
// write code here
//若只有一个节点返回另一个,两个都为null自然返回null
if(t1 == null){
return t2;
}
if(t2 == null){
return t1;
}
//根左右的方式递归
TreeNode head = new TreeNode(t1.val + t2.val);
head.left = mergeTrees(t1.left, t2.left);
head.right = mergeTrees(t1.right,t2.right);
return head;
}
}
解题思路:
根据二叉树镜像的定义,考虑递归遍历(dfs)二叉树,交换每个节点的左 / 右子节点,即可生成二叉树的镜像。
解题步骤:
1、特判:如果pRoot为空,返回空
2、交换左右子树
3、把pRoot的左子树放到Mirror中镜像一下
4、把pRoot的右子树放到Mirror中镜像一下
5、返回根节点root
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param pRoot TreeNode类
* @return TreeNode类
*/
public TreeNode Mirror (TreeNode pRoot) {
// write code here
if(pRoot == null){
return pRoot;
}
//左右子树交换
TreeNode temp = pRoot.left;
pRoot.left = pRoot.right;
pRoot.right = temp;
//递归左右子树
Mirror(pRoot.left);
Mirror(pRoot.right);
return pRoot;
}
}
思路:
二叉搜索树的特性就是中序遍历是递增序。既然是判断是否是二叉搜索树,那我们可以使用中序递归遍历。只要之前的节点是二叉树搜索树,那么如果当前的节点小于上一个节点值那么就可以向下判断。只不过在过程中我们要求反退出。比如一个链表1->2->3->4,只要for循环遍历如果中间有不是递增的直接返回false即可。
if(root.val < pre)
return false;
具体做法:
public class Solution {
int pre = Integer.MIN_VALUE;
public boolean isValidBST (TreeNode root) {
// write code here
//中序遍历
if(root == null){
return true;
}
//先进入左子树
if(!isValidBST(root.left)){
return false;
}
if(root.val < pre){
return false;
}
//更新最值
pre = root.val;
//再进入右子树
return isValidBST(root.right);
}
}
思路:
对完全二叉树最重要的定义就是叶子节点只能出现在最下层和次下层,所以我们想到可以使用队列辅助进行层次遍历——从上到下遍历所有层,每层从左到右,只有次下层和最下层才有叶子节点,其他层出现叶子节点就意味着不是完全二叉树。
具体做法:
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param root TreeNode类
* @return bool布尔型
*/
public boolean isCompleteTree (TreeNode root) {
// write code here
//空树一定是完全二叉树
if(root == null){
return true;
}
//辅助队列
Queue<TreeNode> q = new LinkedList<>();
//根节点加入队列
q.offer(root);
//从队列中取出的节点
TreeNode cur;
//定义一个首次出现的标记位
boolean notComplete = false;
while(!q.isEmpty()){
cur = q.poll();
//标记第一次遇到空节点
if(cur == null){
notComplete = true;
//退出
continue;
}
//后续访问已经遇到空节点了
if(notComplete){
return false;
}
q.offer(cur.left);
q.offer(cur.right);
}
return true;
}
}
思路:
从题中给出的有效信息:
故此 首先想到的方法是使用递归的方式判断子节点的状态
具体做法:
如果一个节点的左右子节点都是平衡的,并且左右子节点的深度差不超过 1,则可以确定这个节点就是一颗平衡二叉树。
public class Solution {
public boolean IsBalanced_Solution (TreeNode pRoot) {
// write code here
//递归
if(pRoot == null){
return true;
}
//判断左右子树是否符合规则,且深度不能超过2
return IsBalanced_Solution(pRoot.left) && IsBalanced_Solution(pRoot.right) && Math.abs(deep(pRoot.left) - deep(pRoot.right))< 2;
}
public int deep(TreeNode root){
if(root == null){
return 0;
}
return Math.max(deep(root.left), deep(root.right)) + 1;
}
}
思路:
我们可以利用二叉搜索树的性质:对于某一个节点若是p与q都小于等于这个这个节点值,说明p、q都在这个节点的左子树,而最近的公共祖先也一定在这个节点的左子树;若是p与q都大于等于这个节点,说明p、q都在这个节点的右子树,而最近的公共祖先也一定在这个节点的右子树。而若是对于某个节点,p与q的值一个大于等于节点值,一个小于等于节点值,说明它们分布在该节点的两边,而这个节点就是最近的公共祖先,因此从上到下的其他祖先都将这个两个节点放到同一子树,只有最近公共祖先会将它们放入不同的子树,每次进入一个子树又回到刚刚的问题,因此可以使用递归。
具体做法:
public class Solution {
public int lowestCommonAncestor (TreeNode root, int p, int q) {
// write code here
//递归
//空树找不到公共祖先
if(root == null){
return -1;
}
//pq在该节点两边说明该节点就是最近公共祖先
if((p >= root.val && q <= root.val) || (p <= root.val && q >= root.val)){
return root.val;
}
//pq都在该节点的左边
else if(p <= root.val && q <= root.val){
//进入左子树
return lowestCommonAncestor(root.left, p , q);
}//pq都在该节点的右侧
else{
//进入右子树
return lowestCommonAncestor(root.right, p, q);
}
}
}
思路:
我们可以讨论几种情况:
public class Solution {
public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
// write code here
//该子树为空,返回-1
if(root == null){
return -1;
}
//该节点是其中某一个节点
if(root.val == o1 || root.val == o2){
return root.val;
}
//左子树寻找公共祖先
int left = lowestCommonAncestor(root.left, o1, o2);
//右子树寻找公共祖先
int right = lowestCommonAncestor(root.right, o1, o2);
//左子树中没找到,则在右子树中
if(left == -1){
return right;
}
//右子树没有找到,则在左子树中
if(right == -1){
return left;
}
//否则是当前节点
return root.val;
}
}
思路:
序列化即将二叉树的节点值取出,放入一个字符串中,我们可以按照前序遍历的思路,遍历二叉树每个节点,并将节点值存储在字符串中,我们用‘#’表示空节点,用‘!'表示节点与节点之间的分割。
反序列化即根据给定的字符串,将二叉树重建,因为字符串中的顺序是前序遍历,因此我们重建的时候也是前序遍历,即可还原。
具体做法:
SerializeFunction(root, res);
//根节点
str.append(root.val).append('!');
//左子树
SerializeFunction(root.left, str);
//右子树
SerializeFunction(root.right, str);
TreeNode res = DeserializeFunction(str);
TreeNode root = new TreeNode(val);
......
//反序列化与序列化一致,都是前序
root.left = DeserializeFunction(str);
root.right = DeserializeFunction(str);
import java.util.*;
public class Solution {
//序列的下标
public int index = 0;
//处理序列化的功能函数(递归)
private void SerializeFunction(TreeNode root, StringBuilder str) {
//如果节点为空,表示左子节点或右子节点为空,用#表示
if (root == null) {
str.append('#');
return;
}
//根节点
str.append(root.val).append('!');
//左子树
SerializeFunction(root.left, str);
//右子树
SerializeFunction(root.right, str);
}
public String Serialize(TreeNode root) {
//处理空树
if (root == null)
return "#";
StringBuilder res = new StringBuilder();
SerializeFunction(root, res);
//把str转换成char
return res.toString();
}
//处理反序列化的功能函数(递归)
private TreeNode DeserializeFunction(String str) {
//到达叶节点时,构建完毕,返回继续构建父节点
//空节点
if (str.charAt(index) == '#') {
index++;
return null;
}
//数字转换
int val = 0;
//遇到分隔符或者结尾
while (str.charAt(index) != '!' && index != str.length()) {
val = val * 10 + ((str.charAt(index)) - '0');
index++;
}
TreeNode root = new TreeNode(val);
//序列到底了,构建完成
if (index == str.length())
return root;
else
index++;
//反序列化与序列化一致,都是前序
root.left = DeserializeFunction(str);
root.right = DeserializeFunction(str);
return root;
}
public TreeNode Deserialize(String str) {
//空序列对应空树
if (str == "#")
return null;
TreeNode res = DeserializeFunction(str);
return res;
}
}
思路:
对于二叉树的前序遍历,我们知道序列的第一个元素必定是根节点的值,因为序列没有重复的元素,因此中序遍历中可以找到相同的这个元素,而我们又知道中序遍历中根节点将二叉树分成了左右子树两个部分
具体做法:
public class Solution {
public TreeNode reConstructBinaryTree (int[] pre, int[] vin) {
// write code here
int n = pre.length;
int m = vin.length;
//每个遍历都不能为0
if (n == 0 || m == 0) {
return null;
}
//构建根节点
TreeNode root = new TreeNode(pre[0]);
for (int i = 0; i < m; i++) {
//找到中序遍历中的前序第一个元素
if (pre[0] == vin[i]) {
//构建左子树
root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1),
Arrays.copyOfRange(vin, 0, i));
//构建右子树
root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length),
Arrays.copyOfRange(vin, i + 1, vin.length));
break;
}
}
return root;
}
}
思路:
首先呢根据上一题的建树思路,拿到树;然后采用层序遍历的方式 + 辅助队列,最后返回结果
具体做法:
step 1:首先检查树是否为空,为空就不打印。
step 2:建立队列辅助层次遍历,根节点先进队。
step 3:用一个size变量,每次进入一层的时候记录当前队列大小,等到size为0时,便到了最右边,记录下该节点元素。
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 求二叉树的右视图
* @param preOrder int整型一维数组 先序遍历
* @param inOrder int整型一维数组 中序遍历
* @return int整型一维数组
*/
public int[] solve (int[] preOrder, int[] inOrder) {
// write code here
//层次遍历
//先拿到重建的二叉树
TreeNode tree = reConstructBinaryTree(preOrder, inOrder);
if (tree == null) {
return new int[] {};
}
Queue<TreeNode> q = new LinkedList<>();
q.add(tree);
List<Integer> res = new ArrayList<>();
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; ++i) {
//取出来de节点
TreeNode cur = q.poll();
//加入到结果集中
//这里是关键,将每一层的最后一个元素加入到res中
if (i == size - 1) {
res.add(cur.val);
}
//看当前节点有没有左右孩子,有的话加入到队列
if (cur.left != null) {
q.offer((cur.left));
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
//封装右视图
int[] result = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
result[i] = res.get(i);
}
return result;
}
//重建二叉树
public TreeNode reConstructBinaryTree (int[] pre, int[] vin) {
// write code here
int n = pre.length;
int m = vin.length;
//每个遍历都不能为0
if (n == 0 || m == 0) {
return null;
}
//构建根节点
TreeNode root = new TreeNode(pre[0]);
for (int i = 0; i < m; i++) {
//找到中序遍历中的前序第一个元素
if (pre[0] == vin[i]) {
//构建左子树
root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1),
Arrays.copyOfRange(vin, 0, i));
//构建右子树
root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length),
Arrays.copyOfRange(vin, i + 1, vin.length));
break;
}
}
return root;
}
}