首页 > 其他分享 >树:剑指 Offer 07. 重建二叉树

树:剑指 Offer 07. 重建二叉树

时间:2023-03-29 16:37:53浏览次数:33  
标签:preorder 遍历 07 Offer 中序 右子 二叉树 inorder 节点

题目描述:

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

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

 

示例 1:

 

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

 

示例 2:

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

 

限制:

  0 <= 节点个数 <= 5000

 

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

以题目示例为例:

  ·前序遍历划分 [ 3 | 9 | 20 15 7 ]
  ·中序遍历划分 [ 9 | 3 | 15 20 7 ]

 

根据以上性质,可得出以下推论:

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

 

通过以上三步,可确定 三个节点 :1.树的根节点、2.左子树根节点、3.右子树根节点。

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

 

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

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

  •递推工作:

    1.建立根节点 node : 节点值为 preorder[root] ;
    2.划分左右子树: 查找根节点在中序遍历 inorder 中的索引 i ;


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

  3.构建左右子树: 开启左右子树递归;


  •返回值: 回溯返回 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<Integer, Integer> 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;                                           // 回溯返回根节点
    }
}

 

标签:preorder,遍历,07,Offer,中序,右子,二叉树,inorder,节点
From: https://www.cnblogs.com/zhz123567/p/17269399.html

相关文章

  • 【永嘉原厂技术支持】超低功耗LCD液晶段码屏显示驱动IC-VKL076 SSOP28,19*4 76点阵,超低
    VKL076概述:VKL076是一个点阵式存储映射的LCD驱动器,可支持最大76点(19SEGx4COM)的LCD屏。单片机可通过I2C接口配置显示参数和读写显示数据,可配置4种功耗模式,也可通过关显示......
  • LeetCode 101.对称二叉树
    1.题目:给你一个二叉树的根节点 root ,检查它是否轴对称。 示例1:输入:root=[1,2,2,3,4,4,3]输出:true2.代码:方法一:递归实现/***Definitionforabinarytreenode.......
  • Gym104076L Tree Distance
    Gym104076LTreeDistance题目链接。\(\text{difficulty}={4,2.5}\)。\(\text{tags}=点分治,扫描线\)。没见过确实想不到。由于查询是区间对区间,分块等数据结构并不好......
  • 对称的二叉树
    classSolution{public:booldfs(TreeNode*l,TreeNode*r){if(l==NULL&&r==NULL)returntrue;elseif(l&&r)re......
  • 二叉树的镜像
    classSolution{public:voidmirror(TreeNode*root){if(root==NULL)return;mirror(root->left);mirror(root->right);Tre......
  • P1005 [NOIP2007 提高组] 矩阵取数游戏
    思维题:显然每个行可以互相独立来处理。贪心和暴力显然都不容易处理这题,所以我们只能考虑dp。每次只能取最左边和最右边的数,这显然很符合区间dp的特点。所以我们令dp[i]......
  • 面试题59 - II. 队列的最大值(剑指offer)
    题目描述:请定义一个队列并实现函数max_value得到队列里的最大值,要求函数max_value、push_back和pop_front的均摊时间复杂度都是O(1)。若队列为空,pop_front和max_v......
  • 用 Go 剑指 Offer 04. 二维数组中的查找
    在一个n*m的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数......
  • 用 Go 剑指 Offer 09. 用两个栈实现队列
    用两个栈实现一个队列。队列的声明如下,请实现它的两个函数appendTail和deleteHead,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHe......
  • 剑指offer11(Java)-旋转数组中的最小值(简单)
    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。给你一个可能存在 重复 元素值的数组 numbers ,它原来是一个升序排列的数组,并按上述情形进行......