• leetcode刷题(133)——剑指 Offer 07. 重建二叉树


    输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。

    假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

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

    Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
    Output: [3,9,20,null,null,15,7]
    
    • 1
    • 2

    示例 2:

    Input: preorder = [-1], inorder = [-1]
    Output: [-1]
    
    • 1
    • 2

    解题思路:

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

    以题目示例为例:

    前序遍历划分 [ 3 | 9 | 20 15 7 ]
    中序遍历划分 [ 9 | 3 | 15 20 7 ]
    根据以上性质,可得出以下推论:

    前序遍历的首元素 为 树的根节点 node 的值。
    在中序遍历中搜索根节点 node 的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。
    根据中序遍历中的左(右)子树的节点数量,可将 前序遍历 划分为 [ 根节点 | 左子树 | 右子树 ] 。

    在这里插入图片描述
    通过以上三步,可确定 三个节点 :1.树的根节点、2.左子树根节点、3.右子树根节点。

    根据「分治算法」思想,对于树的左、右子树,仍可复用以上方法划分子树的左右子树。

    分治算法解析:
    递推参数: 根节点在前序遍历的索引 root 、子树在中序遍历的左边界 left 、子树在中序遍历的右边界 right ;

    终止条件: 当 left > right ,代表已经越过叶节点,此时返回 nullnull ;

    递推工作:

    建立根节点 node : 节点值为 preorder[root] ;
    划分左右子树: 查找根节点在中序遍历 inorder 中的索引 i ;
    为了提升效率,本文使用哈希表 dic 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1)O(1) ;

    构建左右子树: 开启左右子树递归;
    在这里插入图片描述
    TIPS: i - left + root + 1含义为 根节点索引 + 左子树长度 + 1

    返回值: 回溯返回 node ,作为上一层递归中根节点的左 / 右子节点;

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

    注意:本文方法只适用于 “无重复节点值” 的二叉树。

    class Solution {
        int[] preorder;
        HashMap dic = new HashMap<>();
        public TreeNode buildTree(int[] preorder, int[] inorder) {
            this.preorder = preorder;
            for(int i = 0; i < inorder.length; i++)
                dic.put(inorder[i], i);
            return recur(0, 0, inorder.length - 1);
        }
        TreeNode recur(int root, int left, int right) {
            if(left > right) return null;                          // 递归终止
            TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
            int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树
            node.left = recur(root + 1, left, i - 1);              // 开启左子树递归
            node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
            return node;                                           // 回溯返回根节点
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    R语言中的取整函数
    flutter 命令
    Linux和本地Windows如何互传文件(sz和rz指令)
    c高级 shell指令
    (C++)把字符串转换成整数
    Gin:获取本机IP,获取访问IP
    C++ 语法基础课 习题1 —— 变量、输入输出、顺序语句
    【Pandas数据处理100例】(一百):Pandas中使用filter()过滤器实现数据筛选
    机器学习和数据挖掘01- lasso regularization
    软件测试---场景法(功能测试)
  • 原文地址:https://blog.csdn.net/u012124438/article/details/128033351