106.从中序与后序遍历序列构造二叉树
如果你是不知道理论的,那就得仔细分析了,
举个例子:
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]
在这个实例中结合我们对中序遍历(左中右)和后序遍历(左右中)的了解我们不难发现这其中肯定有一定的联系(当然题目都这么出,肯定暗藏玄机啦),
你看,你仔细看:
- 中序遍历–>通过中间节点把左右节点都分开了
- 而后序遍历又正好摆明了对应数组的最后一个元素就是当前的中间节点
那么关键来了,如何把一个小规律推广到代码中实现对应构造二叉树的功能呢?
这摆明了,就是让你使用递归嘛,(一个大树又可以分成无数个小树)
具体就是我们每取出一个postorder的最后一个元素,就通过这个元素的数值来找到其在inorder的位置,然后左边为左子树,右边为右子树,如此循环往复,就可以了.
递归的退出条件则是:当要用来构造左子树的部分为null ||构造右子树的部分为null(如何得出这个条件呢?–>当时的我会觉得就算构造左子树的部分null了,那么我们不也可以接着构造右子树吗?然后才发现在这个情况下直接return是没有问题的,右子树的的部分会在上一个栈帧去接着递归(终究是题刷少了))(但是我们再想把||换成&&可以吗?当然不可以,要是你左边没有了,而右边有,岂不是会因此给再new左边节点,甚至可能空指针)(我们写这个退出条件主要就是要同时让左右子树都能正常按我们的逻辑进行)
代码如下:
写代码时还要注意对每个区间的取值
class Solution {
//利用hashmap建立索引来快速查找postorder[postorder.length-1]
Map<Integer,Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map=new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i],i);
}
return getNode(inorder,0,inorder.length,postorder,0,postorder.length);
}
public TreeNode getNode(int[]inorder,int inBegin,int inEnd,int[]postorder,int postBegin,int postEnd){
//以下关于区间全部使用左闭右开
if(inBegin>=inEnd||postBegin>=postEnd){
return null;
}
int middleIndex=map.get(postorder[postEnd-1]);
TreeNode middleNode=new TreeNode(postorder[postEnd-1]);
int lenOfLeft=middleIndex-inBegin;
middleNode.left=getNode(inorder,inBegin,middleIndex,postorder,postBegin,postBegin+lenOfLeft);
middleNode.right=getNode(inorder,middleIndex+1,inEnd,postorder,postBegin+lenOfLeft,postEnd-1);
return middleNode;
}
}
105从前序与中序遍历序列构造二叉树
其实差不多,我们上面那个是利用后序遍历的最后一个就是中间节点,
而前序只不过是第一个就是中间节点.
代码如下:
class Solution {
Map<Integer,Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
//老方法递归
//与之前的中序后序的区别是换成中序和前序
//其实基本上差不多
//在中序后序的破解上
//核心无非就是找到中节点
//前序与后序无非是一个在最前面一个在最后面
map=new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i],i);
}
//一样的递归逻辑在这就省略了
return getNode(inorder,0, inorder.length, preorder,0, preorder.length);
}
public TreeNode getNode(int[]inorder,int inBegin,int inEnd,int[]preorder,int preBegin,int preEnd){
//一样的左闭右开
//退出条件
if(inBegin>=inEnd||preBegin>=preEnd){
return null;
}
int middleIndex=map.get(preorder[preBegin]);
TreeNode node=new TreeNode(inorder[middleIndex]);
int lenOfLeft=middleIndex-inBegin;
node.left=getNode(inorder,inBegin,middleIndex,preorder,1+preBegin,preBegin+lenOfLeft+1);
node.right=getNode(inorder,middleIndex+1,inEnd,preorder,lenOfLeft+preBegin+1,preEnd);
//不对劲,原先以为可以硬套,结果发现,还是我们需要reverse一下,
//三思过后,还是可以的,就是和那啥相反一下就可以了
//我们这个preorder还有一个地方需要减1,应该不用了,我们通过+lenOfLeft跳过了
return node;
}
}