7. 重建二叉树(剑指 Offer 题解Java版)

7. 重建二叉树

题目链接

牛客网

题目描述

根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
在这里插入图片描述

解题思路

前序遍历序列的第一个元素 3 就是二叉树的根节点,中序遍历序列的根节点 3 把这个序列分成两半部分,分别是[9]和[20,15,7],左半分部是根节点的左子树,右半分布是根节点的右,树。,

基于这个特点,我们可以采用递归的方法来做,其大致逻辑如下。
1、通过前序序列第一个元素确定根节点(例如 3)。
2、通过根节点把中序序列分成两个序列,一个是左子树序列([9]),一个是右子树序列([15,20,7)。
3、通过左右子树的中序序列可以求出前序遍历的左右子树序列(左:[9],右:[20,15,7])。
4、左右子树的前序序列第一个元素分别是根节点的左右儿子。
5、通过递归重复以上步骤(看代码吧,看了代码可能就好理解点了)。

前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。然后分别对左右子树递归地求解。
在这里插入图片描述

package 重建二叉树;
/*
作者     :XiangLin
创建时间 :21/02/2020 22:32
文件     :ReConstructBinaryTree.java
IDE      :IntelliJ IDEA
*/

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

        public TreeNode(int val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return "TreeNode{" +
                    "val=" + val +
                    ", left=" + left +
                    ", right=" + right +
                    '}';
        }
    }

//    // 缓存中序遍历数组每个值对应的索引
//    private Map<Integer, Integer> indexForInOrders = new HashMap<>();

    public  TreeNode reConstructBinaryTree(int[] pre, int[] in) {
        if (pre == null || in == null) { //如果前序或者中序有一个是空直接返回
            return null;
        }
        TreeNode root;
        root = rebuildTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
        return root;
    }

    /**
     *
     * @param pre 前序列表
     * @param preStart 前序序列的起位置
     * @param preEnd 前序序列的起位置
     * @param in 中序列表
     * @param inStart 中序序列的起位置
     * @param inend 中序序列的起位置
     * @return
     */
    // preStart-preEnd表示前序序列的起始位置,inStart-inEnd也一样表示中序序列的起始位置
    private TreeNode rebuildTree(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inend) {
        if (preStart > preEnd | inStart > inend) { //停止递归的条件
            return null;
        }
        //根节点
        TreeNode root = new TreeNode(pre[preStart]);
        // 寻找根节点在中序序列的位置
        for (int i = inStart; i <= inend; i++) {
            if (in[i] == pre[preStart]) {
                // 可以计算出中序序列的左右子树序列为:左:inStart~i -1,右:i+1~inEnd。
                // 前序序列的左右子树:左:preStart+1~preStart+i-inStart,右:preStart+i-inStart+1~preEnd
                root.left = rebuildTree(pre, preStart + 1, preStart + i - inStart, in, inStart, i - 1);
                root.right = rebuildTree(pre, preStart + i - inStart + 1, preEnd, in, i + 1, inend);
            }
        }
        return root;
    }

    public static void main(String[] args) {
        ReConstructBinaryTree r = new ReConstructBinaryTree();
        int preorder[] = {3,9,20,15,7};
        int inorder[] = {9,3,15,20,7};
        TreeNode treeNode =r.reConstructBinaryTree(preorder, inorder);
        System.out.println(treeNode);
    }
}

输出:
TreeNode{val=3, left=TreeNode{val=9, left=null, right=null}, right=TreeNode{val=20, left=TreeNode{val=15, left=null, right=null}, right=TreeNode{val=7, left=null, right=null}}}

The best way to achieve a goal is to devote 100% of your time and energy to it.
达到目标的最好办法就是投入自己百分百的时间和精力去完成它

个人微信公众号,专注于学习资源、笔记分享。我们一起成长,一起学习。一直纯真着,善良着,温情地热爱生活。
五角钱的程序员,专注于学习资源、笔记分享。
XiangLin
2020年2月23日于重庆城口
好好学习,天天向上,终有所获

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值