Leetcode 剑指 Offer II 055. 二叉搜索树迭代器

题目难度: 中等

原题链接

今天继续更新 Leetcode 的剑指 Offer(专项突击版)系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~

题目描述

实现一个二叉搜索树迭代器类 BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:

  • BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。
  • boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true ;否则返回 false 。
  • int next()将指针向右移动,然后返回指针处的数字。
  • 注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。

可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。

示例:

  • 输入
    • inputs = [“BSTIterator”, “next”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”]
    • inputs = [[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]
  • 输出
    • [null, 3, 7, true, 9, true, 15, true, 20, false]
  • 解释
    • BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);
    • bSTIterator.next(); // 返回 3
    • bSTIterator.next(); // 返回 7
    • bSTIterator.hasNext(); // 返回 True
    • bSTIterator.next(); // 返回 9
    • bSTIterator.hasNext(); // 返回 True
    • bSTIterator.next(); // 返回 15
    • bSTIterator.hasNext(); // 返回 True
    • bSTIterator.next(); // 返回 20
    • bSTIterator.hasNext(); // 返回 False

提示:

  • 树中节点的数目在范围 [1, 10^5] 内
  • 0 <= Node.val <= 10^6
  • 最多调用 10^5 次 hasNext 和 next 操作

进阶:

  • 你可以设计一个满足下述条件的解决方案吗?next() 和 hasNext() 操作均摊时间复杂度为 O(1) ,并使用 O(h) 内存。其中 h 是树的高度。

题目思考

  1. 如何利用二叉搜索树的性质?
  2. 如何尽可能优化 next() 和 hasNext() 操作的时间复杂度?

解决方案

思路
  • 分析题目, 一个很容易想到的思路就是中序遍历, 将二叉搜索树转换成一个有序列表, 存储递增的值
  • 然后维护一个当前下标, 每次 next() 操作返回对应的值, 并把下标右移一位即可
  • 不过这样虽说 next() 和 hasNext() 操作的时间复杂度都是 O(1), 不过需要额外使用 O(N)的内存, 不满足进阶要求, 如何优化呢?
  • 如果我们可以直接对原树进行改造, 将其转换成一颗递增顺序树 (根节点最小, 每个节点的右子节点指向大于它的最小节点), 并维护下个节点 nex, 这样每次 next()操作只需要返回 nex 的值, 并将 nex 设为其右子节点即可
  • 这个改造过程正是前面刚做过的题目Leetcode 剑指 Offer II 052. 递增顺序搜索树, 为了方便起见, 我把对应的思路也贴在这里了:
    • 回顾二叉搜索树的性质, 其中序遍历的节点本身就是有序的, 所以如果我们保存了前一个节点, 那么在遍历当前节点时, 只需要将前一个节点的右子节点指向它即可, 然后将前一节点更新为当前节点, 以此类推, 这样最终中序遍历完成时, 就得到了题目要求的递增顺序搜索树
    • 当然, 我们在遍历到当前节点时, 也需要将其左子节点置为空, 这里之所以将当前节点而不是前一节点的左子节点置为空, 是因为这样才能保证最终所有节点的左子节点都是空, 否则最后一个节点的左子节点就可能不是空, 会导致出现循环
    • 利用上述做法, 我们就无需引入额外的列表存储, 也不需要再次遍历了
    • 另外在遍历第一个节点时, 由于它没有前一节点, 所以我们可以额外引入一个哨兵节点, 并将最开始的前一节点初始化为哨兵, 这样哨兵的右子节点就是最终形成的树的根, 返回它即可
  • 这样我们就只需要在初始化时, 使用 O(h)的空间来改造树, 之后的 next() 和 hasNext() 操作都只需要 O(1)的时间复杂度
  • 下面代码中有详细的注释, 方便大家理解
复杂度
  • 时间复杂度 O(N)/O(1): 初始化时只需要遍历每个节点一次, 为 O(N); next() 和 hasNext() 操作只需要常数时间, 为 O(1)
  • 空间复杂度 O(H): 初始化改造树时的递归调用最多使用 O(H) 栈空间, H 是树的高度
代码
class BSTIterator:def __init__(self, root: TreeNode):dummy = TreeNode(0)pre = dummydef inorder(node):# 中序遍历nonlocal preif not node:returninorder(node.left)# 将当前节点的左子节点置为空, 注意不能将pre的左子节点置为空, 否则会漏掉最后一个节点node.left = None# 将前一节点的右子节点指向当前节点pre.right = node# 更新前一节点为当前节点pre = nodeinorder(node.right)inorder(root)self.nex = dummy.rightdef next(self) -> int:res = self.nex.val# 移动self.nex到中序遍历的下一个节点self.nex = self.nex.rightreturn resdef hasNext(self) -> bool:return self.nex != None

大家可以在下面这些地方找到我~😊

我的 GitHub

我的 Leetcode

我的 CSDN

我的知乎专栏

我的头条号

我的牛客网博客

我的公众号: 算法精选, 欢迎大家扫码关注~😊

算法精选 - 微信扫一扫关注我

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux破解用户密码【基于redhat9】

Linux破解用户密码【基于redhat9】 操作步骤&#xff1a; 重启虚拟机&#xff0c;选择第二行&#xff0c;按下e键在倒数第二行的末尾加入 rd.break,按下ctrlx键&#xff0c;进入终端界面重新挂载/sysroot为读写切换到bash修改用户密码创建 /.autorelabel 文件使SELinux安全策略…

[HTML]Web前端开发技术6(HTML5、CSS3、JavaScript )DIV与SPAN,盒模型,Overflow——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

深入理解Docker容器核心技术

文章目录 1. Linux命名空间&#xff08;Namespaces&#xff09;1.1 示例&#xff1a;PID命名空间 2. 控制组&#xff08;cgroups&#xff09;2.1 示例&#xff1a;内存控制组 3. 联合文件系统&#xff08;UnionFS&#xff09;3.1 示例&#xff1a;查看镜像的分层结构 4. Docker…

【数电笔记】逻辑代数的基本定律、常用公式

目录 说明&#xff1a; 逻辑代数的基本定律 1. 常量间的运算 2. 逻辑变量与常量的运算 3. 与普通代数相似的定律 4. 摩根定律&#xff08;反演律&#xff09; 5. 等式证明方法例题 逻辑代数的常用公式 1. 吸收律 2. 冗余律 3. 示例应用 4. 关于异或运算的一些公式 …

Leetcode—2661.找出叠涂元素【中等】

2023每日刷题&#xff08;四十六&#xff09; Leetcode—2661.找出叠涂元素 题意解读 题目意思就是&#xff0c;按照arr数组从左到右的顺序遍历各个arr[i]&#xff0c;涂抹这个值在矩阵中对应位置的网格&#xff0c;一旦你发现它所在的行或者列满员了&#xff0c;就返回这个i…

AT89S52单片机------中断系统

目录 单片机的内部结构 中断请求标志寄存器 (1)TCON寄存器 (2)SCON寄存器 (3)定时器2的控制寄存器T2CON 中断允许与中断优先级的控制寄存器 中断允许寄存器IE 中断优先级寄存器IP 响应中断请求的条件 外部中断响应时间 外部中断的触发方式选择 中断请求的撤销 1.定…

Tomcat目录介绍

目录 1 Tomcat主目录介绍 2 webapps目录介绍 3 Tomcat配置文件目录介绍&#xff08;conf&#xff09; 1 Tomcat主目录介绍 进入Tomcat目录下&#xff0c;我的目录是/application/tomcat/ cd /application/tomcat/ 安装tree命令 yum -y install tree tree -L 1 tree&…

智慧农田可视化大数据综合管理平台方案,EasyCVR助力农业高质量发展

一、背景需求 我国是农业大国&#xff0c;农业耕地面积达到20亿亩。随着物联网、大数据、人工智能等新一代信息技术与农业农村加速融合&#xff0c;以及国家对农业的重视&#xff0c;智慧农业对于我国农业现代化建设和实施乡村振兴战略具有重大引领与推动作用。在传统农田生产…

【Redis】Redis的内部设计与实现

Redis的设计、实现 数据结构和内部编码 type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串)hash(哈希)、list(列表)、set(集合)、zset (有序集合),但这些只是Redis对外的数据结构。 实际上每种数据结构都有自己底层的内部编码实现,而且是多种实现,…

户外电力检测设备,如何实现远程数据实时互通?

北京某企业专注于电力设备的局部放电检测与监测技术的研究与实践应用&#xff0c;可提供局部放电开关柜检测、高频局部放电发电机检测、电力设备绝缘检测等方案。 在实际项目实施过程&#xff0c;企业工作人员需要在各地电力设施部署放电监测设备并进行检测。由于经常涉及户外的…

Sentinel核心类解读:Node

基本介绍 Sentinel中的簇点链路是由一个个的Node组成的&#xff0c;Node是一个接口。Node中保存了对资源的实时数据的统计&#xff0c;Sentinel中的限流或者降级等功能就是通过Node中的数据进行判断的。 Sentinel中是这样描述Node的&#xff1a; Holds real-time statistics…

基于单片机设计的智能水泵控制器

一、前言 在一些场景中&#xff0c;如水池、水箱等水体容器的管理中&#xff0c;保持水位的稳定是至关重要的。传统上&#xff0c;人们通常需要手动监测水位并进行水泵的启停控制&#xff0c;这种方式不仅效率低下&#xff0c;还可能导致水位过高或过低&#xff0c;从而对水体…

Hdoop学习笔记(HDP)-Part.15 安装HIVE

十五、安装HIVE 1.配置MetaStore 利用ambari创建的MySQL作为MetaStore&#xff0c;创建用户hive及数据库hive mysql -uroot -p CREATE DATABASE hive; CREATE USER hive% IDENTIFIED BY lnydLNsy115; GRANT ALL ON hive.* TO hive%; FLUSH PRIVILEGES;2.安装 在服务中添加H…

【数据结构】循环链表和双向链表

【循环链表】 (有头结点) pR1->next; R1->nextR2->next->next; free(R2->next); R2->nextp; 例&#xff1a;对于两个单循环链表a&#xff0c;b&#xff0c;将其连接起来&#xff0c;变成一个单循环链表 #include<stdio.h> #include<stdlib.h> …

关于前端的学习思考-父子盒子溢出问题

先摆图片 很明显&#xff0c;大盒子高度设置400px&#xff0c;小盒子都是高度设置成300px&#xff0c;明显400px<600px&#xff0c;这时候子盒子就会溢出。如何解决溢出问题&#xff1f; 这个时候我把子盒子换成50%&#xff0c;50%。发现并不会溢出&#xff0c;因为相当于两…

springboot缓存技术-Ehcache-Redis-memcached

springboot缓存技术-Ehcache-Redis-memcached 文章目录 springboot缓存技术-Ehcache-Redis-memcachedspring缓存使用方式手机验证码案例缓存供应商变更Ehcache变更缓存供应商Redis缓存供应商变更memcached下载安装memcachedSpringBoot整合memcached spring缓存使用方式 导缓存…

异常处理啊

异常处理 异常 程序运行过程中&#xff0c;发生错误导致异常退出&#xff08;不是程序的语法问题&#xff0c;而是代码的逻辑问题&#xff0c;编译不出错&#xff09;。 e.g. string 字符串&#xff0c;使用 at 函数访问其中的字符元素时&#xff0c;如果越界&#xff0c;程…

2022年高校大数据挑战赛B题图像信息隐藏求解全过程论文及程序

2022年高校大数据挑战赛 B题 图像信息隐藏 原题再现&#xff1a; 互联网的快速发展&#xff0c;给图像、视频的传播方式带来巨大变化。图像作为媒体的重要载体&#xff0c;每天有大量的原创图像公开在互联网上&#xff0c;如何保护图像版权的同时不破坏原始的图像一直是图像处…

代码随想录刷题题Day3

刷题的第三天&#xff0c;希望自己能够不断坚持下去&#xff0c;迎来蜕变。&#x1f600;&#x1f600;&#x1f600; 刷题语言&#xff1a;C / Python Day3 任务 ● 链表理论基础 ● 203.移除链表元素 ● 707.设计链表 ● 206.反转链表 1 链表理论基础 链表&#xff1a;通过…

卷积神经网络(VGG-16)猫狗识别

文章目录 一、前言二、前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 再次检查数据3. 配置数据集4. 可视化数据 三、构建VG-16网络四、编译五、训练模型六、模型评估七、保存and加载模型八、预测…