题目:输入某二叉树的前序遍历和中序遍历的结果,请重新构造出该二叉树。假设输入的前序遍历和中序遍历的结果中不包含重复的数字。例如输入的前序遍历序列为{1,2,4,7,3,5,6,8}和中序遍历为{4,7,2,1,5,3,6,8},则重建出二叉树并输出它的头结点。

前序遍历:根节点--》左节点--》右节点

中序遍历:左节点--》根节点--》右节点

后序遍历:左节点--》右节点--》根节点

在二叉树的前序遍历序列中,第一个数字总是树的根节点的值。但在中序遍历中,根节点的值在序列的中间,左子树的结点的值位于根节点的值的左边,而右子树的结点的值位于根节点的右边。因此我们需要扫描中序遍历序列,才能找到根节点的值。

如图所示,前序遍历序列的第一个数字1就是根节点的值。扫描中序遍历序列,就能确定根节点的值的位置。根据中序遍历的特点,在根节点的值1前面3个数字都是左子树结点的值,位于1后面的数字都是右子树结点的值。

由于中序遍历序列中,有3个数字是左子树结点的值,因此左子树总共有3个左子结点。同样,在前序遍历的序列中,根节点后面的3个数字就是3个左子树结点的值,再后面的所有数字都是右子树结点的值。这样我们就在前序遍历和中序遍历两个序列中,分别找到了左右子树对应的子序列。

然后再根据左子树的前序遍历和中序遍历找出根节点和左右子树,可以使用递归来完成,每次得到根节点

用左子树来举例:

第二次:

前序:247

中序:472

根节点2,由中序可知没有右节点

第三次:

前序:47

中序:47

根节点:4

没有了左子树,7为4的右节点

代码如下:

/**
* 树节点
*/
class BinaryTreeNode {
int value;
BinaryTreeNode leftNode;
BinaryTreeNode rightNode;
public BinaryTreeNode(int value){
this.value=value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public BinaryTreeNode getLeftNode() {
return leftNode;
}
public void setLeftNode(BinaryTreeNode leftNode) {
this.leftNode = leftNode;
}
public BinaryTreeNode getRightNode() {
return rightNode;
}
public void setRightNode(BinaryTreeNode rightNode) {
this.rightNode = rightNode;
} } public class RebuildTree {
/**
* 根据前序遍历和中序遍历重建二叉树
* */
public static BinaryTreeNode rebuildTree(int[] preOrder, int[] inOrder){
if (preOrder == null || inOrder == null || preOrder.length == 0 || inOrder.length == 0 || preOrder.length != inOrder.length) {
return null;
}
//根节点
BinaryTreeNode root=new BinaryTreeNode(preOrder[0]);
root.setLeftNode(null);
root.setRightNode(null);
//左子树节点的个数
int leftNum=0;
for(int i=0;i<inOrder.length;i++){
if(inOrder[i]==root.getValue()){
break;
}else{
leftNum++;
}
}
//右子树节点的个数
int rightNum=inOrder.length-1-leftNum; //重建左子树
while(leftNum>0){
//用来存放左子树的前序遍历
int leftPreOrder[]=new int[leftNum];
//用来存放左子树的中序遍历
int leftInOrder[]=new int[leftNum];
//赋值给左子树每个节点值,把左子树再独立成一棵树
for(int i=0;i<leftNum;i++){
leftPreOrder[i]=preOrder[i+1];
leftInOrder[i]=inOrder[i];
}
BinaryTreeNode leftRoot=rebuildTree(leftPreOrder, leftInOrder);
root.setLeftNode(leftRoot);
}
//重建右子树
while(rightNum>0){
//右子树的前序遍历
int rightPreOrder[]=new int[rightNum];
//右子树的中序遍历
int rightInOrder[]=new int[rightNum];
//赋值 for(int i=0;i<rightNum;i++){
rightPreOrder[i]=preOrder[i+1+leftNum];
rightInOrder[i]=preOrder[i+1+leftNum];
}
BinaryTreeNode rightNode=rebuildTree(rightPreOrder, rightInOrder);
root.setRightNode(rightNode);
} return root;
} public static void main(String[] args) {
// 二叉树的先序序列
int[] preOrder = { 1, 2, 4, 7, 3, 5, 6, 8 };
// 二叉树的中序序列
int[] inOrder = { 4, 7, 2, 1, 5, 3, 8, 6 };
BinaryTreeNode root = rebuildTree(preOrder, inOrder);
}
}

剑指offer第二版面试题6:重建二叉树(JAVA版)的更多相关文章

  1. 《剑指offer》面试题6 重建二叉树 Java版

    (由一个二叉树的前序和中序序列重建一颗二叉树) 书中方法:我们要重建一棵二叉树,就要不断地找到根节点和根节点的左子结点和右子节点.注意前序序列, 它的第一个元素就是二叉树的根节点,后面的元素分为它的左 ...

  2. 剑指offer第二版面试题7:二叉树的下一个节点(JAVA版本)

    题目:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析: 根据中序遍历的特点,要找到一个节点的下一个节点无非 ...

  3. 剑指offer第二版面试题4:替换空格(JAVA版)

    题目:请实现一个函数,把字符串中的每个空格替换成“%20”.例如输入“We are happy”,则输出”We%20are%20happy”. 原因:在网络编程中,如果URL参数中含有特殊字符,如:空 ...

  4. 剑指offer第二版面试题5:从尾到头打印链表(JAVA版)

    题目描述: 输入一个链表,从尾到头打印链表每个节点的值.返回新链表. import java.util.Stack; //定义链表结构 class ListNode { int value; List ...

  5. 剑指offer第二版面试题11:旋转数组的最小数字(JAVA版)

    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ...

  6. 剑指offer第二版面试题10:斐波那契数列(JAVA版)

    题目:写一个函数,输入n,求斐波那契数列的第n项.斐波那契数列的定义如下: 1.效率很低效的解法,挑剔的面试官不会喜欢 使用递归实现: public class Fibonacci { public ...

  7. 剑指offer第二版面试题9:用两个队列实现栈(JAVA版)

    题目:用两个队列实现栈. 分析:通过一系列的栈的压入和弹出操作来分析用队列模拟一个栈的过程,如图所示,我们先往栈内压入一个元素a.由于两个队列现在都是空,我们可以选择把a插入两个队列中的任一个.我们不 ...

  8. 剑指offer第二版面试题8:用两个栈实现队列(JAVA版)

    题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 分析: 我们通过一个具体的例子来分析 ...

  9. 剑指offer第二版面试题3:二维数组中的查找(JAVA版)

    题目: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 1 2 8 9 2 4 ...

随机推荐

  1. 分布式调度框架TBSchedule使用方法

    一.TBSchedule简介 TBSchedule是来自淘宝的分布式调度开源框架,基于Zookeeper纯Java实现,其目的是让一种批量任务或者不断变化的任务,能够被动态的分配到多个主机的JVM中的 ...

  2. java并发编程笔记(四)——安全发布对象

    java并发编程笔记(四)--安全发布对象 发布对象 使一个对象能够被当前范围之外的代码所使用 对象逸出 一种错误的发布.当一个对象还没构造完成时,就使它被其他线程所见 不安全的发布对象 某一个类的构 ...

  3. C/s模式&&B/S模式

    C/s模式:是客户端/服务器(Client/Server)模式,主要指的是传统的桌面级的应用程序.比如我们经常用的信息管理系统. C/S 客户端/服务器 例如QQ,网络游戏,需要下载客户端才能访问服务 ...

  4. dir(dict)|字典的创建-添加-删除-修改-判断存在-取值等相关操作

    dir(dict) ####字典操作:创建-添加-删除-修改-判断存在-取值 #(一)创建字典: {} .等号. zip(). [(),()] #1.创建空字典 dict0 = {} #2.等号创建 ...

  5. java 重新学习 (六)

    一.java7以后,使用带泛型的接口,类定义变量,那么调用构造器创建对象时构造器的后面不必带上泛型.List<String> list = new ArrayList()<>; ...

  6. jmeter beanshell postprocessor 使用

    String newtoken=bsh.args[0];print(newtoken);${__setProperty(newtoken,${token},)}; String newcompanyI ...

  7. 构建局域网YUM仓库

    修改yum源为阿里云源 检验阿里云源是否正常 yum repolist Loaded plugins: fastestmirror Loading mirror speeds from cached ...

  8. 第一记 搭建Java集成开发环境

    一.JDK JDK可以前往oracle官网进行下载并进行安装(我这边使用的是jdk1.8版本,也推荐使用jdk1.8及以上的) 下图是默认路径安装完成后的截图 安装完成会产生这两个文件夹 二.配置环境 ...

  9. 获取图片地址url的后缀名

    getNameFromLink(url){ if(url.indexOf('.cn/') !== -1){          return (url.split('.')[url.split('.') ...

  10. stdio - 标准输入输出库函数

    SYNOPSIS 总览 #include <stdio.h> FILE *stdin; FILE *stdout; FILE *stderr; DESCRIPTION 描述 标注 I/O ...