您的位置:首页 > Web前端

剑指offer--<重建二叉树>

2017-03-19 15:46 309 查看
题目描述:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

题目条件:数组前序+数组中序

题目要求:重现二维数组

理论知识:二叉树,前序遍历 ,中序遍历 ,一开始忘了前序遍历和中序遍历,翻了一下数据结构,前序遍历,先处理当前节点,再处理左子树,最后处理右子树,中序遍历,先处理左子树,再处理当前节点,最后处理右子树,附:前,中,后是指的当前节点。

自己思路:

1. 前序遍历,先处理当前节点,所以,比较容易找节点,中序遍历的有个明显的特点,就是当前节点的左子树,就在当前节点的左边,所以先找根节点,通过前序遍历来确定根节点,子树根节点,中序遍历来确定,属于左子树还是右子树。

2.第一次执行程序之后,可以得到根节点,左子树和右子树,将左子树(右子树)继续当做一棵树(递归),继续执行程序,就可以确定每个节点。

3. 思考的过程中,发现确定根节点的过程类似于快速排序实现,每次递归。

具体代码(原创):

/**
* 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 [] in) {
//pre,in的大小始终是相同的。
TreeNode root=null;
if (pre.length==0)//处理空树
{
return root;
}
root=getTree(pre,in);//放入参数,进行递归处理
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private  TreeNode getTree(int[] pre, int[] in) {
TreeNode treeNode= new TreeNode(pre[0]);//通过前序找好子树根节点
if (pre.length==1)//处理树中只有一个根节点
{
treeNode.left=null;
treeNode.right=null;
return treeNode;
}
int irank=getIrank(0,pre,in);//确定数的根节点在中序的下标
if ((irank>0)&(irank<pre.length-1))//树有左子树and右子树
{
int[] plow=new int[irank];//low 代表左子树部分,左子树前序列表
int[] ilow=new int[irank];//左子树中序列表
int[] phigh=new int[in
b533
.length-irank-1];//high 代表右子树部分,右子树前序列表
int[] ihigh=new int[in.length-irank-1];//high 代表右子树部分,右子树中序列表
ilow://根据子树跟节点切分中序得到左边部分
for (int i=0;i<irank;i++ )
{
ilow[i]=in[i];
}
plow://根据子树跟节点切分前序得到左边部分
for (int i=0;i<irank;i++ )
{
plow[i]=pre[i+1];
}
treeNode.left=getTree(plow,ilow);//左子树递归
ihigh://根据子树跟节点切分中序得到右边部分
for (int i=irank+1;i<in.length;i++ )
{
ihigh[i-irank-1]=in[i];
}

phigh://根据子树跟节点切分中序得到右边部分
for (int i=irank+1;i<pre.length;i++ )
{
phigh[i-irank-1]=pre[i];
}
treeNode.right=getTree(phigh,ihigh);//you右子树递归
}
else if((irank>0))////树有左子树
{
int[] plow=new int[irank];
int[] ilow=new int[irank];
ilow://根据子树跟节点切分中序得到左边部分
for (int i=0;i<irank;i++ )
{
ilow[i]=in[i];
}

plow://根据子树跟节点切分前序得到左边部分
for (int i=0;i<irank;i++ )
{
plow[i]=pre[i+1];
}
treeNode.right=null;
treeNode.left=getTree(plow,ilow);
}
else if(irank<pre.length-1)//树有右子树
{
//int[] plow=new int[irank];
//int[] ilow=new int[irank];
int[] ihigh=new int[in.length-irank-1];
int[] phigh=new int[in.length-irank-1];

ihigh://根据子树跟节点切分中序得到右边部分
for (int i=irank+1;i<in.length;i++ )
{
ihigh[i-irank-1]=in[i];
}

phigh://根据子树跟节点切分中序得到右边部分
for (int i=irank+1;i<pre.length;i++ )
{
phigh[i-irank-1]=pre[i];
}
treeNode.left=null;
treeNode.right=getTree(phigh,ihigh);

}
return treeNode;
}

private int getIrank(int prank,int[] pre, int[] in)
{

for (int i=0;i<in.length;i++)
{
if(pre[prank]==in[i])
{
return i;
}
}
return prank;
}

}


再贴一下,牛客呼声比较高的代码:

/**
* 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 [] 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]);//每次都是用原来的pre,而我的是每次都生成一个新的,这个更好
for(int i=startIn;i<=endIn;i++)//还存在子树
if(in[i]==pre[startPre])//找到根节点位置i
{
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);
}
return root;
}
}


代码 托管GitHub:https://github.com/johnlee2018/JZoffer.git
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: