剑指offer——重建二叉树

简介: 剑指offer——重建二叉树

剑指offer——重建二叉树(亚马逊面试题)


原题描述

输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
注意:
二叉树中每个节点的值都互不相同;
输入的前序遍历和中序遍历一定合法;
样例
给定:
前序遍历是:[3, 9, 20, 15, 7]
中序遍历是:[9, 3, 15, 20, 7]
返回:[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉树如下所示:
    3
   / \
  9  20
    /  \
   15   7
原题链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/

参考代码(c++版)

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    map<int,int> hash;
    vector<int> preorder,inorder;
    TreeNode* buildTree(vector<int>& _preorder, vector<int>& _inorder) {
        preorder = _preorder,inorder= _inorder;
        for(int i = 0; i < inorder.size();i++) hash[inorder[i]] = i;
        return dfs(0,preorder.size()-1,0,inorder.size()-1);
    }
    TreeNode* dfs(int pl,int pr,int il, int ir)
    {
        if(pl>pr) return nullptr;
        auto root = new TreeNode(preorder[pl]);
        int k = hash[root->val];
        auto left = dfs(pl+1,pl+1+k-il-1,il,k-1);
        auto right = dfs(pl+1+k-il,pr,k+1,ir);
        root->left = left;
        root->right = right;
        return root;
    }
};

解析


涉及知识点


1.树:n(n >= 0)个结点构成的有限集合。

微信图片_20221017125349.jpg

2.二叉树:每个结点最多有两个子树(左子树和右子树)的树结构

3.前序遍历:先访问根节点,再依次遍历左子树和右子树

4.中序遍历:先遍历左子树,再访问根节点,最后遍历右子树

5.后序遍历:先遍历左子树,再遍历右子树,最后访问根节点

6.由两种遍历序列确定二叉树–> 必须要有中序遍历。微信图片_20221017125505.jpg

前序是根左右,后序是左右根。都可以很快的确定根。但是对于左右子树的确定就存在争议。比如例子中的两个序列,都知道A是根,但是现在B是左子树还是右子树了?


分析


根据先序遍历序列的第一个结点确定根节点


根据根节点在中序遍历序列中分割出左右两个子序列


对左子树和右子树分别递归使用相同的方法继续分解

微信图片_20221017125557.jpg


为了快速找到数据,考虑使用哈希表进行优化(哈希表可以实现近似O(1)时间复杂度的插入、删除、查找等操作)


代码逐步落实


1.因为之后要在递归函数中使用到前序序列和中序序列。将两个序列处理为全局变量

vector<int> preorder,inorder;
//return dfs(0,preorder.size()-1,0,inorder.size()-1);

2.记录中序序列中每个数据的位置,用于后文的查询

for(int i = 0; i< inorder.size() ; i++) hash[inorder[i]] = i;

3,编写核心的递归函数dfs(int pl,int pr,int il,int ir)

pl,pr,il,ir分别代表前序序列的左端点、右端点和中序遍历序列的左端点、右端点

1.特判——倘若传入的序列里面没有元素,返回空

if(pl > pr) return nullptr;

2.获取根节点信息

auto root = new TreeNode(preorder[pl]);

3,计算根节点的哈希值

int k = hash[root->val];

4.对左右子树分别递归使用相同方法继续分解

auto left = dfs(pl+1,pl+k-il,il,k-1);
auto right = dfs(pl+k-il+1,pr,k+1,ir);

5.将最终结果返回到根节点root,维护为一棵完整的树

root->left = left, root->right = right;

难点剖析


步骤3-4 中取区间范围是比较棘手的点


理解

核心是谨记这句话"对左右子树分别递归使用相同方法继续分解"


处理左子树


结合上图,对于前序遍历而言,左子树所在的区间是pl+1 ~ (pl+1)+(k-il)-1,经过合并,就得到了上述表达式pl+1 ~ pl+k-il。对于中序遍历而言,左子树所在的区间是il ~ k-1。


处理右子树


结合上图,对于前序遍历而言,右子树所在的区间是(pl+k-il+1) ~ pr。对于中序遍历而言,右子树所在的区间是(k+1) ~ ir


相关文章
绘梦相似,AIGC图生图:相似图像生成模型魔搭社区开源体验
日常我们在艺术创作和产品设计中,需要多张风格相似的图片
|
C语言
【C语言刷题系列】计算整数的二进制位中1的个数 (三种方式)
【C语言刷题系列】计算整数的二进制位中1的个数 (三种方式)
|
关系型数据库 应用服务中间件 nginx
使用docker快速搭建服务器环境
思路 将nginx、mysql、tomcat等环境打包为一个个docker,然后使用docker-compose管理。 服务器内安装docker相关环境,然后直接运行docker-compose配置,即可快速搭建完成服务器环境。
8697 14
|
缓存 程序员 内存技术
STM32定时器配置(TIM1-TIM8)高级定时器+普通定时器,定时计数模式下总结
STM32定时器配置(TIM1-TIM8)高级定时器+普通定时器,定时计数模式下总结
1503 0
|
Android开发
Android TabLayout修改选中字体大小
Android TabLayout修改选中字体大小
2114 0
Android TabLayout修改选中字体大小
|
传感器 安全 物联网
5G物联网安全测试对于DDOS攻击防护
DDoS分布式拒绝服务攻击,已经变得越来越常见,越来越强大,很多攻击者都在使用物联网设备, 来建立更多的连接和带宽,以及5G网络跟云应用的发展, 随着暗网和加密货币的出现和匿名性,越来越多的人从暗网中发动DDOS攻击。
533 18
5G物联网安全测试对于DDOS攻击防护
|
SQL 分布式计算 安全
《CDP企业数据云平台从入门到实践》——CDP平台的安全和治理(3)
《CDP企业数据云平台从入门到实践》——CDP平台的安全和治理(3)
244 0
|
存储 安全 Java
Java集合 - ConcurrentHashMap
本篇文章介绍 Java 集合中的 ConcurrentHashMap。 1、CHM 的底层存储结构; 2、CHM 的新增操作的处理逻辑; 3、CHM 的数组扩容机制; 4、CHM 的查询操作的处理逻辑; 5、CHM 的计数;
245 0
直播平台源代码,这样选择才是最佳方案
直播平台源代码是开发直播平台的最佳选择方案,为什么这么说?
648 0
直播平台源代码,这样选择才是最佳方案