题目:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
理解前序遍历,中序遍历,后序遍历
前序遍历:中,左,右
中序遍历:左,中,右
后序遍历:左,右,中
例如:这是一个二叉树
前序遍历:124356
中序遍历:421536
后序遍历:425631
理解给出前序和中序推断出二叉树结构
依上图为例:
前序遍历:124356
中序遍历:421536
分析:前序遍历的第一个结点为根节点。中序遍历的根节点在中间,左边为左子树的中序遍历结果,右边为右子树的中序遍历结果。
前序遍历:124356 --> 1是根节点
中序遍历:421536 -->由上得知 42 1 536
前序遍历:124356 -->由上得知 1 24 356
结论:1是根节点,24是左子树的前序遍历,356是右子树的前序遍历,42是左子树的中序遍历,536是右子树的中序遍历。
左子树分析:
前序:24 -->2是左子树根节点
中序:42 -->4是左子树根节点的左子树无右子树
右子树分析:
前序:356 --> 3 是右子树根节点
中序:536 --> 5 3 6
综上所述:由此可推断二叉树的结构。还原二叉树
--------1-----------
—2--------3-------
4---------5-----6----
```java
public static TreeNode reConstructBinaryTree(int[] pre, int[] in) {
TreeNode tree = new TreeNode(pre[0]);
if (pre.length == in.length && pre.length == 1) {
return tree;
}
if (pre.length == in.length && pre.length == 2) {//只含有左子树或者右子树
if (pre[0] == in[0]) {// in[1]是in[0]的右子树
tree.right = new TreeNode(pre[1]);
} else {// in[1]是in[0]的左子树无右子树
tree.left = new TreeNode(pre[1]);
}
return tree;
}
if (pre.length == 3) {//左右子树都含有
if(pre[0]==in[1]){
tree.left = new TreeNode(in[0]);
tree.right = new TreeNode(in[2]);
return tree;
}
}
int index=-1;//记录根节点在中序遍历的位置
for(int i=0;i<in.length;i++){//通过根结点寻找出左右子树数组
if(in[i]==pre[0]){//找出根节点
index=i;
break;
}
}
int[] leftPre=new int[index];//左子树前序
int[] leftIn=new int[index];//左子树中序
int[] rightPre=new int[pre.length-1-index];//右子树前序
int[] rightIn=new int[pre.length-1-index];//右子树中序
//给左子树和右子树的前序遍历数组赋值
for(int j=1;j<=index;j++){//给leftpre赋值
//从索引为1的位置开始截取pre的index位树给leftpre
leftPre[j-1]=pre[j];
}
for(int j=index+1;j<pre.length;j++){//给rightpre赋值
//把pre后几位给rightpre
rightPre[j-index-1]=pre[j];
}
//给左子树和右子树的中序遍历数组赋值
for(int j=0;j<index;j++){//给左子树的中序遍历数组赋值
//把in的前index位截取给leftin
leftIn[j]=in[j];
}
for(int j=index+1;j<in.length;j++){//给右子树的中序遍历数组赋值
//把in的后index位截取给rightin
rightIn[j-index-1]=in[j];
}
if(leftPre.length!=0){
tree.left=reConstructBinaryTree(leftPre, leftIn);
}
if(rightPre.length!=0){
tree.right=reConstructBinaryTree(rightPre, rightIn);
}
return tree;
}
``` // 前序遍历
public static void preShow(TreeNode tree) {
System.out.print(tree.val);
if (tree.left != null) {
preShow(tree.left);
} else {
System.out.print("#");
}
if (tree.right != null) {
preShow(tree.right);
} else {
System.out.print("#");
}
}
// 中序遍历
public static void inShow(TreeNode tree) {
if (tree == null) {
return;
}
if (tree.left != null) {
inShow(tree.left);
} else {
System.out.print("#");
}
System.out.print(tree.val);
if (tree.right != null) {
inShow(tree.right);
} else {
System.out.print("#");
}
}
}
public static void main(String[] args) {
int[] pre = { 1, 2, 4, 3, 5, 6 };
int[] in = { 4, 2, 1, 5, 3, 6 };
TreeNode tree = reConstructBinaryTree(pre, in);
preShow(tree);
System.out.println();
inShow(tree);
}
评论区大神解法:
因为是树的结构,一般都是用递归来实现。
用数学归纳法的思想就是,假设最后一步,就是root的左右子树都已经重建好了,那么我只要考虑将root的左右子树安上去即可。
根据前序遍历的性质,第一个元素必然就是root,那么下面的工作就是如何确定root的左右子树的范围。
根据中序遍历的性质,root元素前面都是root的左子树,后面都是root的右子树。那么我们只要找到中序遍历中root的位置,就可以确定好左右子树的范围。
正如上面所说,只需要将确定的左右子树安到root上即可。递归要注意出口,假设最后只有一个元素了,那么就要返回。
```java
import java.util.Arrays;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
//数组长度为0的时候要处理
if(pre.length == 0){
return null;
}
int rootVal = pre[0];
//数组长度仅为1的时候就要处理
if(pre.length == 1){
return new TreeNode(rootVal);
}
//我们先找到root所在的位置,确定好前序和中序中左子树和右子树序列的范围
TreeNode root = new TreeNode(rootVal);
int rootIndex = 0;
for(int i=0;i<in.length;i++){
if(rootVal == in[i]){
rootIndex = i;
break;
}
}
//递归,假设root的左右子树都已经构建完毕,那么只要将左右子树安到root左右即可
//这里注意Arrays.copyOfRange(int[],start,end)是[)的区间
root.left = reConstructBinaryTree(Arrays.copyOfRange(pre,1,rootIndex+1),Arrays.copyOfRange(in,0,rootIndex));
root.right = reConstructBinaryTree(Arrays.copyOfRange(pre,rootIndex+1,pre.length),Arrays.copyOfRange(in,rootIndex+1,in.length));
return root;
}
}
## 本体小结:
对于树的结构不够熟悉
对递归的理解不够彻底,没有想到最后一步只需安置节点,造成代码不够简洁