题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路:
如果理解了递归的访问,那么建树的过程就容易多了,前序遍历序列的第一个数(后序遍历的最后一个数)一定是根结点,所以可以根据此结点在中序序列中的位置把中序序列分为左子树和右子数两个部分,同样的道理,在左子树和右子数中同样可以用到这样的规律来确定每个中间结点。
自己理解:
先找到根节点,然后根据根节点在寻找根节点的左右节点,递归
代码:
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
if(startPre>endPre||startIn>endIn)
return null;
TreeNode root=new TreeNode(pre[startPre]);
for(int i=startIn;i<=endIn;i++)
if(in[i]==pre[startPre]){
root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
break;
}
return root;
}
}
关键代码解析:
前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
一、root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
1.
弄懂这个图很关键,基本上函数里的形参看着这个图就能够写出来
2.
root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);整个递归最难的地方在于确定左子树先序序列最右边界,也就是startPre+i-startIn这个公式怎么来的。我们知道,不管递归过程是什么样的,先序序列长度和中序序列长度一定要相同,而中序序列的边界是比较好确定的,左子树中中序序列起点是startIn,终点是i-1,左子树中先序序列起点是startPre+1,要求左子树先序序列终点,假设该终点下标为x,根据中序序列长度和先序序列长度相等的条件,得到x-(startPre+1)=i-1-startIn,求得x=i-startIn+startPre,剩下的过程就好理解了。
3.
startpre+1,指的是前序遍历左子树的开始位置,即前序遍历根节点的下一个节点。i-startin,i指的是中序遍历根节点的位置,减去中序遍历开始位置即左子树的长度。所以i-startiin+starpre是前序遍历左子树结束的位置。
4.
搞懂了:i-starin是在计算当前节点左子树节点个数;i-starin+starpre是确定当前节点左子树在pre里的位置;根据中序遍历+前序遍历的特点,pre[starpre+1]就是当前节点的左子节点,pre[i-starin+starpre+1]就是当前节点的右子节点;巧妙的是那个判定条件,越界即左右子节点不存在
前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
二、root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
1.
i-startIn+startPre+1解析:左子树终点:i-startIn+startPre,那么i-startIn+startPre+1就是右子书起点。
三、if(startPre>endPre||startIn>endIn)
return
null
;
1.当startPre = endPre 时说明到了叶子节点,叶子节点的左右子树的指针为空,再往下递归,就是他这条了。个人感觉这里使用等号判断递归结束,返回当前节点更好。