LeetCode 173.二叉搜索树迭代器

news2025/9/21 14:26:19

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

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

示例:

在这里插入图片描述

输入
[“BSTIterator”, “next”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”, “next”, “hasNext”]
[[[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, 105] 内
0 <= Node.val <= 106
最多调用 105 次 hasNext 和 next 操作

进阶:

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

法一:先在构造函数中把整个二叉树的中序遍历存下来:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class BSTIterator {
public:
    BSTIterator(TreeNode* root) 
        : curIdx(0),
          inorderRes()
    {
        inorder(root);
    }
    
    int next() {
        return inorderRes[curIdx++];
    }
    
    bool hasNext() {
        return curIdx < inorderRes.size();
    }

private:
    int curIdx;
    vector<int> inorderRes;

    void inorder(TreeNode *node)
    {
        if (node == nullptr)
        {
            return;
        }

        inorder(node->left);
        inorderRes.push_back(node->val);
        inorder(node->right);
    }
};

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator* obj = new BSTIterator(root);
 * int param_1 = obj->next();
 * bool param_2 = obj->hasNext();
 */

如果树中有n个节点,此算法构造函数的时间复杂度为O(n),next和hasNext方法的时间复杂度为O(1);空间复杂度为O(n),构造函数的栈空间平均需要O(logn),最差需要O(n),存储中序遍历的结果需要O(n)。

法二:手动模拟一个栈:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class BSTIterator {
public:
    BSTIterator(TreeNode* root) {
        curNode = root;
    }
    
    int next() {
        while (curNode != nullptr)
        {
            s.push(curNode);
            curNode = curNode->left;
        }

        curNode = s.top();
        int ret = curNode->val;
        s.pop();
        curNode = curNode->right;

        return ret;
    }
    
    bool hasNext() {
        return !s.empty() || curNode;
    }

private:
    stack<TreeNode *> s;
    TreeNode *curNode;
};

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator* obj = new BSTIterator(root);
 * int param_1 = obj->next();
 * bool param_2 = obj->hasNext();
 */

如果树中有n个节点,此算法构造函数和hasNext方法的时间复杂度为O(1),next方法的时间复杂度平均为O(1),最差为O(n);空间复杂度为O(logn),模拟的栈空间平均需要O(logn),最差需要O(n)。

法三:Morris遍历,核心是将当前节点的前驱结点连到当前节点,这样就不需要栈了,对于中序遍历来说,就是将当前节点的左节点的最右节点指向自身:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class BSTIterator {
public:
    BSTIterator(TreeNode* root) 
        : curNode(root)
    {
    }
    
    int next() {
        if (curNode->left == nullptr)
        {
            int res = curNode->val;
            curNode = curNode->right;
            return res;
        }

        while (curNode->left)
        {
            TreeNode *mostRightOfLeft = getMostRightOfLeft(curNode);
            if (mostRightOfLeft->right == nullptr)
            {
                mostRightOfLeft->right = curNode;
                curNode = curNode->left;
            }
            else if (mostRightOfLeft->right == curNode)
            {
                int res = curNode->val;
                mostRightOfLeft->right = nullptr;
                curNode = curNode->right;
                return res;
            }
        }

        int res = curNode->val;
        curNode = curNode->right;
        return res;
    }
    
    bool hasNext() {
        return curNode;
    }

private:
    TreeNode *curNode;

    TreeNode *getMostRightOfLeft(TreeNode *node)
    {
        TreeNode *cur = node->left;
        while (cur->right != nullptr && cur->right != node)
        {
            cur = cur->right;
        }

        return cur;
    }
};

/**
 * Your BSTIterator object will be instantiated and called as such:
 * BSTIterator* obj = new BSTIterator(root);
 * int param_1 = obj->next();
 * bool param_2 = obj->hasNext();
 */

如果树中有n个节点,此算法构造函数和hasNext方法的时间复杂度为O(1),next方法的时间复杂度平均为O(1),最差为O(n);空间复杂度为O(1)。

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

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

相关文章

C# 视频转图片

在 C# 中将视频转换为图像可以使用 FFmpeg 库。下面是一个示例代码来完成这个任务&#xff1a; using System; using System.Diagnostics;class Program {static void Main(string[] args){string inputFile "input_video.mp4"; // 输入的视频文件路径string outpu…

App前端开发跨平台框架比较:React Native、Flutter、Xamarin等

引言 移动应用开发领域的跨平台框架正在不断演进&#xff0c;为开发者提供更多选择。在本文中&#xff0c;我们将比较几个流行的跨平台框架&#xff1a;React Native、Flutter和Xamarin等。讨论它们的优缺点、适用场景以及开发体验。 第一部分 React Native: 优缺点、适用场景…

【C++ 学习】构造函数详解!!!

1. 类的6个默认成员函数的引入 ① 如果一个类中什么成员都没有&#xff0c;简称为空类。 ② 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 ③ 默认成员函数&#xff1a;用户没有显式实现&…

理解JavaScript中的WeakSet和WeakMap

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【Python】科研代码学习:五 Data Collator,Datasets

【Python】科研代码学习&#xff1a;五 Data Collator&#xff0c;Datasets Data CollatorDefault data collatorDefaultDataCollatorDataCollatorWithPaddingPadding 其他 Data Collator Datasetsload_dataset其他一些基本操作 Data Collator HF官网API&#xff1a;Data Coll…

网易再战腾讯,《永劫无间》宣发捡大漏

《王者荣耀》代言人唯爱《永劫无间》&#xff1f; 最近时代少年团成员严浩翔疑似打赏《永劫无间》女主播一事&#xff0c;在饭圈和游戏圈引起了轩然大波&#xff0c;“男偶像打赏女主播”和“《王者荣耀》代言人爱玩《永劫无间》”&#xff0c;一时不知道哪个行为更炸裂。 虽…

力扣hot100题解(python版63-68题)

63、搜索插入位置 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target 5 输…

Android Studio下载gradle超时问题解决

方法一 1. 配置根目录的setting.gradle.kts文件 pluginManagement {repositories {maven { urluri ("https://www.jitpack.io")}maven { urluri ("https://maven.aliyun.com/repository/releases")}maven { urluri ("https://maven.aliyun.com/repos…

结构体内存对齐详解

目录 结构体对齐&#xff1a; 为什么要进行内存对齐&#xff1f; 关于结构体的详解文章&#xff1a;C语言结构体详解_结构体变量和结构体类型举例-CSDN博客 结构体对齐&#xff1a; 存储的时候和当前存储的成员类型字节大小和默认对齐数比较&#xff0c;取小值 存在该对齐数的…

Windows11安装FFmpeg最新版本

打开终端: 输入 winget install ffmpeg 然后输入 Y 回车后出现如下图: 正在下载FFmpeg 6.1 安装成功 测试

cocos creator 3.7.2使用shader实现图片扫光特效

简介 功能&#xff1a;图片实现扫光效果 引擎&#xff1a;cocos Creator 3.7.2 开发语言&#xff1a;ts 完整版链接 链接https://lengmo714.top/284d90f4.html 效果图 shader代码 // Copyright (c) 2017-2020 Xiamen Yaji Software Co., Ltd. CCEffect %{techniques:- pas…

vue 下载的插件从哪里上传?npm发布插件详细记录

文章参考&#xff1a; 参考文章一&#xff1a; 封装vue插件并发布到npm详细步骤_vue-cli 封装插件-CSDN博客 参考文章二&#xff1a; npm发布vue插件步骤、组件、package、adduser、publish、getElementsByClassName、important、export、default、target、dest_export default…

【开源】SpringBoot框架开发免税店商城管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.2 研究方法 三、系统展示四、核心代码4.1 查询免税种类4.2 查询物品档案4.3 新增顾客4.4 新增消费记录4.5 审核免税 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的免税店商城管理系…

day-18 轮转数组

时间复杂度为O&#xff08;n&#xff09; code: class Solution {public void rotate(int[] nums, int k) {int nnums.length;kk%n;int arr[]new int[n];for(int i0;i<n;i){arr[(ik)%n]nums[i];}for(int i0;i<n;i){nums[i]arr[i];}} }参考答案 进行三次翻转 空间复杂度O…

让开源浏览器Chromium正常显示中文

什么是 Chromium &#xff1f; Chromium 是一个开源浏览器项目&#xff0c;旨在为所有用户构建一种更安全、更快、更稳定的网络体验方式。 和老苏之前介绍的 Firefox 的作用是一样的 文章传送门&#xff1a;给群晖安装firefox浏览器 因为是基于 vnc 的应用&#xff0c;感觉资源…

管理交换机

文章目录 本地管理交换机物理交换机如何本地管理ensp上的虚拟交换机如何本地管理认证模式的三种方式 远程管理交换机配置通过Telnet登录设备配置通过STelnet登录设备 --推荐的方式检查配置结果使用Cloud管理多个交换机时 华为官网配置信息 本地管理交换机 当交换机首次使用时&…

强化学习工具箱(Matlab)

1、Get Started 1.1、MDP环境下训练强化学习智能体 MDP环境如下图 每个圆圈代表一个状态每个状态都有上或下的选择智能体从状态 1 开始智能体接收的奖励值为图中状态转移的值训练目标是最大化累计奖励 &#xff08;1&#xff09;创建 MDP 环境 创建一个具有 8 个状态和 2 …

STM32FreeRTOS任务通知(STM32cube高效开发)

文章目录 一、任务通知(一&#xff09;任务通知概述1、任务通知可模拟队列和信号量2、任务通知优势和局限性 (二) 任务通知函数1、xTaskNotify&#xff08;&#xff09;发送通知值不返回先前通知值的函数2、xTaskNotifyFromISR&#xff08;&#xff09;发送通知函数ISR版本3、x…

Compose UI 之 Small TopAppBar

Small 类型 TopAppBar AppBar 主要由2类&#xff0c;顶部 AppBar 和底部 AppBar。 顶部 AppBar&#xff1a;主要包含了标题&#xff0c;action菜单&#xff0c;导航菜单。底部 AppBar&#xff1a;典型地包含主要导航项。 顶部 AppBar 顶部 AppBar 包含了 4 中类型&#xff…

FREERTOS DAY3

作业&#xff1a;1.总结任务的调度算法&#xff0c;把实现代码再写一下&#xff0c; FreeRTOS中默认的调度算法是 抢占式调度时间片轮转 1.抢占式调度&#xff1a;任务优先级高的可以打断任务优先级低的执行&#xff08;适用于不同优先级&#xff09; 2.时间片轮转&#xff…