分治系列-根据前序和中序遍历重建二叉树

一、题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

示例1:

前序遍历:[3,5,7,8,10]
中序遍历:[7,5,3,8,10]

示例图如下:
在这里插入图片描述

二、解题思路

前序遍历性质: 节点按照 [ 根节点 | 左子树 | 右子树 ] 排序。
中序遍历性质: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序。

​ 在二叉树的前序遍历序列中,第一个数字总是树的根节点的值。但在中序遍历序列中,根节点的值在序列的中间,左子树的节点的值位于根节点的值的左边,而右子树的节点的值位于根节点的值的右边。因此我们需要扫描中序遍历序列,才能找到根节点的值。

​ 以上述事例举例:

在这里插入图片描述

前序遍历的第一元素一定是根节点,设在前序遍历中根节点(子树的根节点)的索引为preIndex,在中序遍历中的索引为currentIndex,如果存在左子树那么左子树的根节点则一定为preIndex + 1(前序遍历中的索引),不存在则为空节点(null);如果存在右子树则右子树的根节点我们无法根据前序遍历求出。这时候我们就需要根据中序遍历确定右子树的根节点,我们可以根据根节点的左子树的长度,来确定右子树的根节点,在前序遍历中可得右子树的根节点索引为:根节点的索引加上左子树元素的长度再加1.所以就能获取中序遍历该节点索引。

​ 根据如上所述,我门能根据根节点求出左子树根节点和右子树根节点,所以在中序遍历中根据根节点划分两个子树,左子树的根节点和右子树根节点我们已求出,这样把原问题划分两个相同的子问题(分治思想),划分的结束条件是该根节点为叶子结点即可。

​ 为了提升效率,本文使用哈希表 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1)

三、代码实现

public class Solution {

    private HashMap<Integer, Integer> posMap = new HashMap<>();

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        //计算中序遍历元素位置
        for(int i = 0; i  < inorder.length; i++){
            posMap.put(inorder[i],i);
        }
        return buildBinaryTree(preorder,0,0,inorder.length - 1);
    }

    /**
     *
     * @param preorder 前序遍历序列
     * @param preIndex 当前子树的根节点索引(前序遍历中的索引)
     * @param leftIndex 当前子树的左边界索引(中序遍历中的索引)
     * @param rightIndex 当前子树的右边界索引(中序遍历中的索引)
     * @return
     */
    private TreeNode buildBinaryTree(int[] preorder,int preIndex,int leftIndex,int rightIndex){
        if(leftIndex > rightIndex ){
            return null;
        }
        int currentIndex = posMap.get(preorder[preIndex]);
        TreeNode root = new TreeNode(preorder[preIndex]);
        root.left = buildBinaryTree(preorder,preIndex + 1,leftIndex,currentIndex -1);
        root.right = buildBinaryTree(preorder,preIndex + currentIndex - leftIndex + 1,currentIndex +1,rightIndex);
        return root;
    }

}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值