剑指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);
    }

    private 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);
    }

    /**
     * Rebuild tree node.
     *
     * @param preOrder 前序遍历序列
     * @param inOrder  中序遍历序列
     * @param preStart 前序遍历开始位置
     * @param preEnd   前序遍历结束位置
     * @param inStart  中序遍历开始位置
     * @param inEnd    中序遍历结束位置
     * @return tree node
     */
    private 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;
    }
}

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值