二叉搜索树题目:二叉搜索树迭代器

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法三
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:二叉搜索树迭代器

出处:173. 二叉搜索树迭代器

难度

4 级

题目描述

要求

实现 BSTIterator \texttt{BSTIterator} BSTIterator 类,表示一个按中序遍历二叉搜索树的迭代器:

  • BSTIterator(TreeNode root) \texttt{BSTIterator(TreeNode root)} BSTIterator(TreeNode root) 初始化 BSTIterator \texttt{BSTIterator} BSTIterator 类的一个对象。二叉搜索树的根结点 root \texttt{root} root 会作为构造函数的一部分给出。指针应初始化为一个不存在于二叉搜索树中且小于二叉搜索树中的任何元素的数字。
  • boolean hasNext() \texttt{boolean hasNext()} boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true \texttt{true} true,否则返回 false \texttt{false} false
  • int next() \texttt{int next()} int next() 将指针向右移动,然后返回指针处的数字。

注意,指针初始化为一个不存在于二叉搜索树中的数字,所以对 next() \texttt{next()} next() 的首次调用将返回二叉搜索树中的最小元素。

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

示例

示例 1:

示例 1

输入:
["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"] \texttt{["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"]} ["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"]
[[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []] \texttt{[[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]} [[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]
输出:
[null, 3, 7, true, 9, true, 15, true, 20, false] \texttt{[null, 3, 7, true, 9, true, 15, true, 20, false]} [null, 3, 7, true, 9, true, 15, true, 20, false]
解释:
BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]); \texttt{BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);} BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);
bSTIterator.next(); \texttt{bSTIterator.next();} bSTIterator.next(); // 返回 3 \texttt{3} 3
bSTIterator.next(); \texttt{bSTIterator.next();} bSTIterator.next(); // 返回 7 \texttt{7} 7
bSTIterator.hasNext(); \texttt{bSTIterator.hasNext();} bSTIterator.hasNext(); // 返回 True \texttt{True} True
bSTIterator.next(); \texttt{bSTIterator.next();} bSTIterator.next(); // 返回 9 \texttt{9} 9
bSTIterator.hasNext(); \texttt{bSTIterator.hasNext();} bSTIterator.hasNext(); // 返回 True \texttt{True} True
bSTIterator.next(); \texttt{bSTIterator.next();} bSTIterator.next(); // 返回 15 \texttt{15} 15
bSTIterator.hasNext(); \texttt{bSTIterator.hasNext();} bSTIterator.hasNext(); // 返回 True \texttt{True} True
bSTIterator.next(); \texttt{bSTIterator.next();} bSTIterator.next(); // 返回 20 \texttt{20} 20
bSTIterator.hasNext(); \texttt{bSTIterator.hasNext();} bSTIterator.hasNext(); // 返回 False \texttt{False} False

数据范围

  • 树中结点数目在范围 [1, 10 5 ] \texttt{[1, 10}^\texttt{5}\texttt{]} [1, 105]
  • 0 ≤ Node.val ≤ 10 6 \texttt{0} \le \texttt{Node.val} \le \texttt{10}^\texttt{6} 0Node.val106
  • 最多调用 10 5 \texttt{10}^\texttt{5} 105 hasNext \texttt{hasNext} hasNext next \texttt{next} next 操作

进阶

你是否可以将 hasNext() \texttt{hasNext()} hasNext() next() \texttt{next()} next() 实现为平均时间复杂度 O(1) \texttt{O(1)} O(1) 并使用 O(h) \texttt{O(h)} O(h) 内存,其中 h \texttt{h} h 是树的高度?

解法一

思路和算法

只要得到二叉搜索树的中序遍历序列,并维护指针指向的下标,即可实现二叉搜索树迭代器。

构造方法中,对给定的二叉搜索树中序遍历,使用列表存储中序遍历的结果,并将指针初始化为指向下标 − 1 -1 1。指针指向的下标为上一个遍历的数字下标, − 1 -1 1 表示尚未遍历任何数字。

对于 hasNext \textit{hasNext} hasNext 操作,需要判断向指针右侧遍历是否存在数字,等价于判断指针指向的下标右侧是否存在数字,因此当指针指向的下标右侧存在数字时返回 true \text{true} true,否则返回 false \text{false} false

对于 next \textit{next} next 操作,将指针向右移动等价于将指针指向的下标加 1 1 1,在更新指针指向的下标之后,返回该下标处的数字。

二叉搜索树的中序遍历可以通过递归、迭代或者莫里斯遍历实现,其中递归实现和迭代实现都需要栈空间,莫里斯遍历使用常数空间,但是由于需要存储中序遍历序列,因此对于结点数为 n n n 的二叉搜索树,都需要 O ( n ) O(n) O(n) 的空间存储中序遍历序列。

代码

下面的代码为递归实现二叉搜索树中序遍历的做法。

class BSTIterator {private List<Integer> traversal;private int index;public BSTIterator(TreeNode root) {traversal = new ArrayList<Integer>();inorder(root);index = -1;}public boolean hasNext() {return index + 1 < traversal.size();}public int next() {return traversal.get(++index);}private void inorder(TreeNode node) {if (node == null) {return;}inorder(node.left);traversal.add(node.val);inorder(node.right);}
}

下面的代码为迭代实现二叉搜索树中序遍历的做法。

class BSTIterator {private List<Integer> traversal;private int index;public BSTIterator(TreeNode root) {traversal = new ArrayList<Integer>();Deque<TreeNode> stack = new ArrayDeque<TreeNode>();TreeNode node = root;while (!stack.isEmpty() || node != null) {while (node != null) {stack.push(node);node = node.left;}node = stack.pop();traversal.add(node.val);node = node.right;}index = -1;}public boolean hasNext() {return index + 1 < traversal.size();}public int next() {return traversal.get(++index);}
}

下面的代码为莫里斯遍历实现二叉搜索树中序遍历的做法。

class BSTIterator {private List<Integer> traversal;private int index;public BSTIterator(TreeNode root) {traversal = new ArrayList<Integer>();TreeNode node = root;while (node != null) {if (node.left == null) {traversal.add(node.val);node = node.right;} else {TreeNode predecessor = node.left;while (predecessor.right != null && predecessor.right != node) {predecessor = predecessor.right;}if (predecessor.right == null) {predecessor.right = node;node = node.left;} else {predecessor.right = null;traversal.add(node.val);node = node.right;}}}index = -1;}public boolean hasNext() {return index + 1 < traversal.size();}public int next() {return traversal.get(++index);}
}

复杂度分析

  • 时间复杂度:构造方法的时间复杂度是 O ( n ) O(n) O(n),方法 hasNext \textit{hasNext} hasNext 和方法 next \textit{next} next 的时间复杂度都是 O ( 1 ) O(1) O(1),其中 n n n 是二叉搜索树的结点数。构造方法需要 O ( n ) O(n) O(n) 的时间对二叉搜索树中序遍历,方法 hasNext \textit{hasNext} hasNext 和方法 next \textit{next} next 根据下标值得到结果,时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。存储中序遍历序列需要 O ( n ) O(n) O(n) 的空间。

解法二

思路和算法

解法一需要存储完整的中序遍历序列,因此空间复杂度与结点数相关。利用中序遍历的迭代实现,可以将空间复杂度降低到与二叉搜索树的高度相关,虽然最坏情况下二叉搜索树的高度等于结点数,但是平均情况下二叉搜索树的高度小于结点数,因此空间复杂度更低。

为了不存储完整的中序遍历序列,不能在构造方法中完成中序遍历,而是应该在 next \textit{next} next 操作中完成中序遍历,每次调用 next \textit{next} next 操作时访问一个结点。因此,需要维护用于迭代实现中序遍历的栈以及当前结点,在构造方法中将栈初始化,并将当前结点初始化为二叉搜索树的根结点。

对于 hasNext \textit{hasNext} hasNext 操作,如果栈不为空或者当前结点不为空则返回 true \text{true} true,否则返回 false \text{false} false

对于 next \textit{next} next 操作,模拟中序遍历的迭代实现的操作,访问一个结点。

代码

class BSTIterator {private Deque<TreeNode> stack;private TreeNode node;public BSTIterator(TreeNode root) {stack = new ArrayDeque<TreeNode>();node = root;}public boolean hasNext() {return !stack.isEmpty() || node != null;}public int next() {while (node != null) {stack.push(node);node = node.left;}node = stack.pop();int val = node.val;node = node.right;return val;}
}

复杂度分析

  • 时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),方法 hasNext \textit{hasNext} hasNext 的时间复杂度是 O ( 1 ) O(1) O(1),方法 next \textit{next} next 的均摊时间复杂度是 O ( 1 ) O(1) O(1)。构造方法初始化栈和当前结点的时间是 O ( 1 ) O(1) O(1),方法 hasNext \textit{hasNext} hasNext 判断栈是否为空和当前结点是否为空的时间是 O ( 1 ) O(1) O(1),方法 next \textit{next} next 的调用过程中会访问每个结点一次且每个结点入栈和出栈各一次,因此均摊时间复杂度是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉搜索树的结点数。空间复杂度主要是栈空间,取决于二叉搜索树的高度,最坏情况下二叉搜索树的高度是 O ( n ) O(n) O(n)

解法三

思路和算法

解法二不是在构造方法中完成中序遍历,而是在 next \textit{next} next 操作中完成中序遍历,避免了存储中序遍历序列,但是由于使用迭代实现中序遍历,仍需要使用栈空间。为了将空间复杂度降低到 O ( 1 ) O(1) O(1),需要使用莫里斯遍历实现中序遍历,在 next \textit{next} next 操作中完成中序遍历。

需要维护用于莫里斯遍历实现中序遍历的当前结点,在构造方法中将当前结点初始化为二叉搜索树的根结点。

对于 hasNext \textit{hasNext} hasNext 操作,如果当前结点不为空则返回 true \text{true} true,否则返回 false \text{false} false

对于 next \textit{next} next 操作,模拟中序遍历的莫里斯遍历实现的操作,访问一个结点。

代码

class BSTIterator {private TreeNode node;public BSTIterator(TreeNode root) {node = root;}public boolean hasNext() {return node != null;}public int next() {int val = -1;while (val < 0) {if (node.left == null) {val = node.val;node = node.right;} else {TreeNode predecessor = node.left;while (predecessor.right != null && predecessor.right != node) {predecessor = predecessor.right;}if (predecessor.right == null) {predecessor.right = node;node = node.left;} else {predecessor.right = null;val = node.val;node = node.right;}}}return val;}
}

复杂度分析

  • 时间复杂度:构造方法的时间复杂度是 O ( 1 ) O(1) O(1),方法 hasNext \textit{hasNext} hasNext 的时间复杂度是 O ( 1 ) O(1) O(1),方法 next \textit{next} next 的均摊时间复杂度是 O ( 1 ) O(1) O(1)。构造方法初始化当前结点的时间是 O ( 1 ) O(1) O(1),方法 hasNext \textit{hasNext} hasNext 判断当前结点是否为空的时间是 O ( 1 ) O(1) O(1),方法 next \textit{next} next 的调用过程中会访问每个结点两次,因此均摊时间复杂度是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( 1 ) O(1) O(1)

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

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

相关文章

计讯物联智慧工业园区系统平台全面提升园区智能化水平

工业园区聚集着各种生产要素&#xff0c;是纺织、机械、家具等诸多产业集中的区域&#xff0c;更是资源消耗和污染物排放的集中地。根据某些工业园区环境调研&#xff0c;园区入驻企业从生产原料到生产制造过程大多带有有毒有害、易燃易爆的特性&#xff0c;再加上装置大型化、…

SpringBoot 热部署。

SpringBoot 热部署。 文章目录 SpringBoot 热部署。 pom.xml。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional…

LeetCode-第137题-只出现一次的数||

1.题目描述 给你一个整数数组 nums &#xff0c;除某个元素仅出现 一次 外&#xff0c;其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 2.样例描述 3.思路描述 先把数组排序&am…

M2TS转MP4怎么转?超快的方法~

M2TS格式的优点主要体现在对高清视频的完美支持&#xff0c;能够提供极致的视觉体验。然而&#xff0c;由于其相对较大的文件大小&#xff0c;有时可能不太适合网络传输。此外&#xff0c;部分不支持M2TS的播放设备可能导致一定的兼容性问题。 想要播放m2ts视频&#xff0c;可…

【kubernetes】关于k8s集群如何将pod调度到指定node节点?

目录 一、k8s的watch机制 二、scheduler的调度策略 Predicate&#xff08;预选策略&#xff09; 常见算法&#xff1a; priorities&#xff08;优选策略&#xff09;常见的算法有&#xff1a; 三、k8s的标签管理之增删改查 四、k8s的将pod调度到指定node的方法 方案一&am…

DFS回溯-经典全排列问题(力扣)

前言 对于全排列问题&#xff0c;常用的做法是设置一个vis数组来确定位置i上的数字是否被访问&#xff0c;因为是全排列问题&#xff0c;所以不同的顺序也是不一样的排列&#xff0c;因此每次都是从起点开始询问**(注意起点到底是0还是1)** 46全排列(最简单的模板) class So…

某资产管理系统打点过程中的免杀经历

上周&#xff0c;被扔过来单位内部的一个链接&#xff0c;让渗透一下&#xff0c;本以为三下五除二很快就能测完&#xff0c;没想到在对抗杀软时费了一番功夫&#xff0c;再加上杂七杂八的事儿&#xff0c;经过了一个星期才测完(&#xff03;&#xffe3;&#xff5e;&#xff…

C#知识点-21(初识数据库)

数据库与内存、文件的比较 内存&#xff1a; 优点&#xff1a;存取速度快 缺点&#xff1a;-容量小 -断电后&#xff0c;数据不会保存 文件&#xff1a; 优点&#xff1a;数据可以持久化保存 缺点&#xff1a;-读取速度慢…

mprpc分布式RPC网络通信框架

mprpc 项目介绍 该项目是一个基于muduo、Protobuf和Zookeeper实现的轻量级分布式RPC网络通信框架。 可以把任何单体架构系统的本地方法调用&#xff0c;重构成基于TCP网络通信的RPC远程方法调用&#xff0c;实现同一台机器的不同进程之间的服务调用&#xff0c;或者不同机器…

下载无水印抖音视频

在抖音看到某些视频想下载&#xff0c;却出现无法保存在本地【显示"作品暂时无法保存,链接已复制"】。或者下载的视频有水印。 而某些微信小程序下载可能需要付费或者有水印。其实我们可以直接使用电脑浏览器直接下载。 举个例子: 这是来自王道官方账号的一条视频链…

基于springboot的某大学外卖系统的实现(源码+论文)

文章目录 目录 文章目录 前言 一、功能设计 二、功能实现 1 后台登录 2管理员界面 3员工信息管理 4客户信息管理 三、库表设计 四、论文 前言 如今&#xff0c;信息化不断的高速发展&#xff0c;社会也跟着不断进步&#xff0c;现今的社会&#xff0c;各种工作都离不开信息化技…

Python基础二

一、变量 在编程中&#xff0c;变量是用来存储数据值的名称。在 Python 中&#xff0c;变量是动态类型的&#xff0c;这意味着你可以将任何类型的数据分配给一个变量&#xff0c;而不需要提前声明变量的类型。 1、全局变量 在函数外部定义的变量是全局变量&#xff0c;可以在程…

boost 编译

参考博客&#xff1a;vs2019 boost 入坑指南 boost下载 官方网站&#xff1a;https://www.boost.org/ 下面以boost_1_73_0为例&#xff1a; boost编译 解压boost_1_73_0.zip运行bootstrap.bat&#xff08;此时目录下会生成b2.exe&#xff09;编译boost b2 install --build…

【vue2项目总结】——动态渲染

文章目录 主页渲染封装接口页面调用传到子组件 搜索列表渲染根据关键字搜索分类id搜索 主页渲染 封装接口 封装准备接口 api/home.js import request from /utils/request// 获取首页数据 export const getHomeData () > {return request.get(/page/detail, {params: {p…

springboot3.x集成SpringDoc Swagger3

近期将springboox2.x升级到了3.x&#xff0c;索性将swagger2也同步升级到swagger3&#xff0c;具体过程如下。 一、添加maven依赖 <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>…

用户角色的重要性:确保财务数据安全的最佳方式

在企业的财务管理业务中&#xff0c;一个人几乎不可能完成所有的财务记账任务&#xff0c;例如设定预算、发票审批等等&#xff0c;至少不能有效地执行。最为明智的方式&#xff0c;是将这些任务分派给特定的人员&#xff0c;比如部门经理、财务经理或者销售、市场人员等等。 但…

C++读取NC数据的结果与真实数值不一致的解决方法

本文介绍基于C 语言的netCDF库读取.nc格式的栅格文件时&#xff0c;代码读取到的数据与栅格文件的实际数据不一致的解决方法。 最近&#xff0c;由于需要读取ERA5气象数据&#xff0c;因此使用C 语言中的netCDF库读取.nc格式文件。其中&#xff0c;偶然发现在Visual Studio的代…

CC攻击的特征和防护措施

随着互联网的快速发展&#xff0c;网络攻击日益频繁。在目前的各种网络攻击中&#xff0c;CC攻击是一种常见的网络攻击手段之一。CC攻击&#xff08;也称为DDoS攻击&#xff09;是指通过大量请求或恶意流量向目标网站或服务器发送请求&#xff0c;以使其服务不可用。可能大家都…

Error:java:JDK isn‘t specified for module “模块名称“

可能是创建模块后不小心删掉了.idea.或.idea出错 只要删除.idea&#xff0c;close project出去&#xff0c;重新进让idea自动下载

VS2022打包C#安装包(最新、最全)

开发c#的一个小工具到打包环境碰壁了&#xff0c;在网上找了很多资料耶踩了很多坑&#xff0c;耗时1hour才打包完毕&#xff0c;避免以后碰到类似的问题再次记录&#xff0c;自认为步骤比较全面&#xff0c;如果有帮助麻烦点个赞呗&#xff01;&#xff01;&#xff01; 一、Mi…