【面试题5 :重建二叉树】

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

image

首先要了解什么是前序遍历、中序遍历和后序遍历,这个概念我已经在《算法》读书笔记的《6、二分搜索树(上)》中详细介绍了。

定义节点类型

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数组第一个元素为根节点root
        //在in数组中找到root位置,那么前面为左孩子中序遍历(假设n个),后面为右孩子中序遍历(假设m个)
        //那么根据这个n和m,就能在pre数组中找到左孩子前序遍历和右孩子前序遍历
        //那么递归的时候,root.left就是【左孩子前序遍历,左孩子中序遍历】,root.right就是【右孩子前序遍历,右孩子中序遍历】
        //这样一直到叶子节点,停止
        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;
    }
}

重构过程

前序遍历:12473568
中序遍历:47215386

  • 前序遍历中的第一个值为树根
  • 树根在中序遍历中的位置,左侧为左子树的中序遍历结果(472),右侧为右子树的中序遍历结果(5386)
  • 在前序遍历中,左子树的前序遍历结果为(247),右子树的前序遍历结果为(3568)
  • 则2为左子树的树根,3为右子树的树根
  • 重复上述操作直至结束

猜你喜欢

转载自blog.csdn.net/sunweiguo1/article/details/80330168