剑指offer第四题-2020-8-27

题目:

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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;
    }
}
## 本体小结:
对于树的结构不够熟悉
对递归的理解不够彻底,没有想到最后一步只需安置节点,造成代码不够简洁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值