B站讲解的这道题是,从中序和前序遍历序列构造二叉树,与当前这道题是一类的,两道题可以一起写,一起看,巩固一下。
目前小编还没有学习map,所以本文章只会用指针的方式去解答本道题,让不会map的小伙伴,也知道怎么做。
目录
1.倒序遍历postorder数组,用postIndex表示当前访问的元素,postIndex初始值==postorder的长度-1,从数组中得到当前根节点Root并创建,然后postIndex--
3.重复执行第一点,获得新的根节点root,然后在inorder数组的区间
2.先把postIndex指向数组末位置,等一下好遍历递归,与此同时,返回一个初始的子方法,_buildTree.(因为实际上我们是在这个方法里面创建树的)
3.回到_buildTree方法,递归创建root的右子树,左子树
题目:
下面以下图的例子作为讲解:
题目给定两个有效的中序和后序遍历的二叉树,可以确定唯一的这颗二叉树。
想要解答本题,你一定要知道的是:
1.在中序遍历的二叉树序列中,某一个节点的左子树一定在该节点的左边(如果有左树)
例如,节点20的左子树是15,在inorder[2],是inorder[3]=20的左边
2.后序遍历的序列的末尾元素一定是此树的根节点
3.由于后序遍历按照的是:左子->右子->根
所以如果我们尝试对postorder倒着遍历(3,20,7....),那么访问顺序就是:
根->右子树->左子树
解题思路(使用递归):
1.倒序遍历postorder数组,用postIndex表示当前访问的元素,postIndex初始值==postorder的长度-1,从数组中得到当前根节点Root并创建,然后postIndex--
2.在inorder数组中找到root节点
注意:
此时,我们可以在inorder数组中找到Root所在下标inorderIndex,这是可以通过inorderIndex下标把inorder数组一分为二
3.重复执行第一点,获得新的根节点root,然后在inorder数组的区间
[inorderIndex-1,inorderIndex.length-1]寻找root节点,如果找到,那么Root.right==root,如果没有找到,那么Root.right==null
代码书写:
1.由于题目接口数量不够,所以我们新创建一个方法,来构建树
2.先把postIndex指向数组末位置,等一下好遍历递归,与此同时,返回一个初始的子方法,_buildTree.(因为实际上我们是在这个方法里面创建树的)
3.回到_buildTree方法,递归创建root的右子树,左子树
findRootInOrder方法(找到inorder数组中,对应root下标)等一下再实现,先把框架搭好
上面代码缺少一个递归终止条件,是什么呢?
如果按照上面的程序递归,begin,end会这样变
{begin,end}=[0,4] [2,4] [4,4] [5,4].........
哎,发现了吧,此时begin竟然大于end,这是不符合常理的,这实际上就说明,右树的创建已经完成了,可以去创建左树了。
因此递归结束条件也就很简单了:
4.findRootInOrder方法的实现:
5.整体代码:
class Solution {
//用begin和end来管理inorder数组--都是int类型
//用postIndex来管理postorder数组--int类型,注意postIndex必须定义为成员变量
private int postIndex;//成员变量,默认初始化为0
private TreeNode _buildTree(int[] inorder,int[] postorder,int begin,int end){
if(begin>end)return null;//返回一个空树
TreeNode root=new TreeNode(postorder[postIndex]);//创建当前的根节点
int inIndex=findRootInOrder(inorder,begin,end,postorder[postIndex]);//找到把inorder数组一分为二的根节点下标
postIndex--;//让指针指向下一个根节点,也就是当前root节点的右子树(如果有)
root.right=_buildTree(inorder,postorder,inIndex+1,end);//右半区间
root.left=_buildTree(inorder,postorder,begin,inIndex-1);//左半区间
return root;//返回创建好的根节点
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postIndex=postorder.length-1;
return _buildTree(inorder,postorder,0,inorder.length-1);//begin和end是闭区间
}
private int findRootInOrder(int[] inorder,int begin,int end,int key){
for (int i = begin; i <=end ; i++) {
if(inorder[i]==key)return i;//找到,返回下标
}
return -1;//这句话一定不会执行,只是为了让编译器不报错,你返回100个w,都没问题
//因为begin,end闭区间如果找不到,递归条件会返回null
}
}