剑指Offer07_重建二叉树

剑指 Offer 07. 重建二叉树

题目:找重建二叉树
  • LeetCode地址:剑指 Offer 07. 重建二叉树

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

  • 示例:

    给出:
    前序遍历 preorder = [3,9,20,15,7]
    中序遍历 inorder = [9,3,15,20,7]
    
    返回如下二叉树:
        3
       / \
      9  20
        /  \
       15   7
    
题解:
方法一:递归
  • 思路:

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

    1. 拿给出的示例来说,从前序遍历我们以可知道 3 必定是根节点;
    2. 又根据 3 在中序遍历数组中的位置可以知 [ 9 ] 必定在其左子树;[ 15, 20, 7 ] 必定在其右子树;
    3. 再看前序遍历数组,可知 [ 9 ] 是 3 节点左子树前序遍历的结果,同时 [ 20, 15, 7 ]是 3 节点右子树前序遍历的结果
    4. 有了上面的分析,我们就可对3节点的左、右子树分别按同样的步骤推理,直到推出整个二叉树。
  • 代码:

    public class Solution {
    
        int[] preorder;
        //存放中序遍历元素值和对应索引 key=元素值 value=中序遍历索引
        HashMap<Integer, Integer> inIndexMap = new HashMap<>();
        
        public TreeNode buildTree(int[] preorder, int[] inorder) {
            this.preorder = preorder;
            int length = preorder.length;
            //中序遍历结果存入inIndexMap
            for(int i = 0; i < length; i++)
                inIndexMap.put(inorder[i], i);
    
            return buildTree(0, 0, length - 1);
        }
    
        /**
         *
         * @param nodePreIndex 当前节点在前序遍历数组中的索引
         * @param left 中序遍历左边界
         * @param right 中序遍历右边界
         * @return 生成的节点
         */
        TreeNode buildTree(int nodePreIndex, int left, int right) {
            if(left > right) return null;
            int nodeVal = preorder[nodePreIndex];
            //根据节点值创建当前节点
            TreeNode node = new TreeNode(nodeVal);
            //获取当前节点中序遍历的索引
            int nodeInIndex = inIndexMap.get(nodeVal);
            //递归创建当前节点的左、右子树
            node.left = buildTree(nodePreIndex + 1, left, nodeInIndex - 1);
            //nodeIndex-left表示左子树节点个数
            //nodePreIndex+nodeIndex-left+1 理解为:当前节点前序索引+左子树节点个数+1 也就是右子节点的索引
            node.right = buildTree(nodePreIndex + nodeInIndex - left + 1, nodeInIndex + 1, right);
            return node;
        }
    
        public static void main(String[] args) {
            int[] preorder = {3, 9, 20, 15, 7};
            int[] inorder = {9, 3, 15, 20, 7};
            TreeNode treeNode = new Solution().buildTree(preorder, inorder);
            System.out.println("treeNode = " + treeNode);
        }
    }
    
  • 复杂度分析:

    • 时间复杂度:O(n) 。其中 N 为树的节点数量。初始化 HashMap 需遍历 inorder ,占用 O(N) 。递归共建立 N个节点,每层递归中的节点建立、搜索操作占用 O(1) ,因此使用 O(N) 时间。
    • 空间复杂度:O(n)。HashMap 使用 O(N) 额外空间。最差情况下,树退化为链表,递归深度达到 N ,占用 O(N) 额外空间;最好情况下,树为满二叉树,递归深度为 logN ,占用 O(logN) 额外空间。
  • 测试:

    image-20201104203812487
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值