剑指Offer-题7(Java版):重建二叉树

参考自:《剑指Offer——名企面试官精讲典型编程题》
以及博客:https://www.cnblogs.com/edisonchou/p/4741099.html

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

主要思路:在二叉树的前序遍历序列中,第一个数字就是树根结点的值。但在中序遍历序列中,根结点的值在序列的中间,左子树的结点的值位于根结点的值的左边,而右子树的结点的值位于根结点的值的右边。因此,通过扫描中序遍历序列,找出根节点位置,进而划分该根节点的左右子树。最后,递归分别重建左子树和右子树。

例如:

            1
         /     \
        2       3
       /       / \
      4       5   6
       \         /
        7       8

前序遍历序列:{1,2, 4, 7, 3, 5, 6, 8 }
中序遍历序列:{4, 7, 2, 1,5, 3, 8, 6 }

根节点:1

左子树前序遍历序列:2, 4, 7
左子树中序遍历序列:4, 7, 2

右子树前序遍历序列:3, 5, 6, 8
右子树中序遍历序列:5, 3, 8, 6

然后递归分别重建左子树和右子树。

关键点:前序遍历特点:第一个元素为根节点。中序遍历特点:根节点左边为左子树,右边为右子树。递归。

时间复杂度:O(树长度),注:时间主要消耗在查找根节点位置

public class ReConstructBinaryTree
{
    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};
//            1
//         /    \
//        2      3
//       /      / \
//      4      5   6
//       \        /
//       7       8
        TreeNode result = reconstructBinaryTree(preOrder, inOrder);
    }

    public static TreeNode reconstructBinaryTree(int[] preOrder, int[] inOrder)
    {
        if (preOrder == null || inOrder == null) return null;
        return rebuild(preOrder, inOrder, 0, preOrder.length - 1, 0, inOrder.length - 1);
    }

    /**
     * @param preOrder 前序遍历序列
     * @param inOrder  中序遍历序列
     * @param preStart 前序遍历开始位置
     * @param preEnd   前序遍历结束位置
     * @param inStart  中序遍历开始位置
     * @param inEnd    中序遍历结束位置
     * @return
     */
    public static TreeNode rebuild(int[] preOrder, int[] inOrder, int preStart, int preEnd,
                                   int inStart, int inEnd)
    {
        if (preStart > preEnd) return null;
        //前序遍历第一个元素就是根节点
        int rootVal = preOrder[preStart];
        int inRootIndex = inStart;  //中序遍历中的根节点位置
        while (inRootIndex <= inEnd)
        {
            //在中序遍历中查找根节点位置
            if (rootVal == inOrder[inRootIndex]) break;
            else inRootIndex++;
        }
        int leftLength = inRootIndex - inStart;  //左子树长度
        TreeNode rootNode = new TreeNode(rootVal); //创建根节点
        int preLeftEnd = preStart + leftLength;
        //创建左子树
        rootNode.left = rebuild(preOrder, inOrder, preStart + 1, preLeftEnd,
                inStart, inRootIndex - 1);
        //创建右子树
        rootNode.right = rebuild(preOrder, inOrder, preLeftEnd + 1, preEnd,
                inRootIndex + 1, inEnd);
        return rootNode;
    }
}

猜你喜欢

转载自blog.csdn.net/m0_37862405/article/details/80068529