LeetCode 173.二叉搜索树迭代器

实现一个二叉搜索树迭代器类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)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Delphi 开箱即用 3】随机生成玩家角色名 (支持男女性别选择)

现在玩家越来越懒了&#xff0c;需要一键生成角色名。这里用Delphi实现自动生成玩家角色名&#xff0c;生成的角色名与手动想出的一样&#xff0c;毫无任何违和感。 效果展示 实现原理 872条姓数据3000条男名数据5000条女名数据 的随机组合&#xff0c;理论上可以根据男女性别…

【Scrapy】京东商品数据可视化

【Scrapy】京东商品数据可视化 文章目录 【Scrapy】京东商品数据可视化  &#x1f449;引言&#x1f48e;一、爬取数据&#xff1a;1.1 scrapy爬虫库简介&#xff1a;1.2 技术实现&#xff1a;1.2.1搭建框架结构1.2.2 分析网页结构 二、数据保存&#xff1a;三、数据读取以及…

【leetcode】429. N 叉树的层序遍历

题目描述 给定一个 N 叉树&#xff0c;返回其节点值的_层序遍历_。&#xff08;即从左到右&#xff0c;逐层遍历&#xff09;。 树的序列化输入是用层序遍历&#xff0c;每组子节点都由 null 值分隔&#xff08;参见示例&#xff09;。 示例 1&#xff1a; 输入&#xff1a;…

Synthetic Temporal Anomaly Guided End-to-End Video Anomaly Detection 论文阅读

Synthetic Temporal Anomaly Guided End-to-End Video Anomaly Detection 论文阅读 Abstract1. Introduction2. Related Work3. Methodology3.1. Architecture3.1.1 Autoencoder3.1.2 Temporal Pseudo Anomaly Synthesizer 3.2. Training3.3. Anomaly Score 4. Experiments4.1.…

R语言更新版本

目录 一、更新R语言 1、安装最新的R语言版本 2、移动之前安装的packages 3、将Rstudio连接到最新的R语言 二、Rstudio更新 一、更新R语言 1、安装最新的R语言版本 查看当前R语言版本&#xff1a; R.version.string 下载最新的R语言安装包&#xff1a;R: The R Project…

王阳明:在心里中一个春天!吃好喝好不等于吃饱喝足,出租屋的第二个周末——早读(逆天打工人爬取热门微信文章解读)

种一个春天&#xff0c;等下一个天亮 引言Python 代码第一篇 霸王别坤第二篇 &#xff08;跳&#xff09;洞见 王阳明&#xff1a;人生若是太苦寒&#xff0c;在心里种一个春天第三篇 人民日报 来了&#xff01;新闻早班车要闻社会政策 结尾 屋宽不如心宽&#xff0c;物整亦是心…

什么是微隔离技术?

微隔离产生的背景 首先来看下南北向流量以及东西向流量的含义 南北向流量 指通过网关进出数据中心的流量&#xff0c;在云计算数据中心&#xff0c;处于用户业务虚拟机&#xff08;容器&#xff09;跟外部网络之间的流量&#xff0c;一般来说防火墙等安全设备部署在数…

基于极大似然算法的系统参数辨识matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于极大似然算法的系统参数辨识。对系统的参数a1&#xff0c;b1&#xff0c;a2&#xff0c;b2分别进行估计&#xff0c;计算估计误差以及估计收敛曲线&#xff0…

【MySQL】表的增删改查——MySQL基本查询、数据库表的创建、表的读取、表的更新、表的删除

文章目录 MySQL表的增删查改1. Create&#xff08;创建&#xff09;1.1 单行插入1.2 多行插入1.3 替换 2. Retrieve&#xff08;读取&#xff09;2.1 select查看2.2 where条件2.3 结果排序2.4 筛选分页结果 3. Update&#xff08;更新&#xff09;3.1 更新单个数据3.2 更新多个…

UE4.27_ParticleSystem(没写完的材料)

UE4.27_ParticleSystem&#xff08;没写完的材料&#xff09; 参考实例&#xff1a; UE4[蓝图]下雪效果及雪的材质的实现

Learn OpenGL 04 纹理

纹理环绕方式 纹理坐标的范围通常是从(0, 0)到(1, 1)&#xff0c;那如果我们把纹理坐标设置在范围之外会发生什么&#xff1f;OpenGL默认的行为是重复这个纹理图像&#xff08;我们基本上忽略浮点纹理坐标的整数部分&#xff09;&#xff0c;但OpenGL提供了更多的选择&#xf…

UI 易用性测试 以及自动化实现!

GUI 是指图形用户界面&#xff0c;UI 是指用户界面&#xff0c;对于纯软件系统&#xff0c;这两者没有本质的区别&#xff0c;GUI易用性测试与 UI 易用性测试内容一致。但是如果测试的对象是一个产品&#xff0c;这两者则存在区别&#xff0c;对于产品 UI 则不仅仅包括 GUI&…

基于springboot+vue实现高校学生党员发展管理系统项目【项目源码+论文说明】

基于springboot实现高校学生党员发展管理系统演示 摘要 随着高校学生规模的不断扩大&#xff0c;高校内的党员统计及发展管理工作面临较大的压力&#xff0c;高校信息化建设的不断优化发展也进一步促进了系统平台的应用&#xff0c;借助系统平台可以实现更加高效便捷的党员信息…

JavaSE面试——Collection接口和Collections类

集合分为&#xff1a;Collection 和 Map 两个体系 java8为 Collection 的父接口( Iterable )提供了一个默认的 Foreach 方法&#xff0c;我们可以使用它进行集合遍历 1. Collection 接口 Collection接口是是Java集合类的顶级接口之一&#xff0c;Collection 接口有 3 种子类型…

RESTful API关键部分组成和构建web应用程序步骤

RESTful API是一种基于HTTP协议的、符合REST原则的应用程序接口。REST&#xff08;Representational State Transfer&#xff09;是一种软件架构风格&#xff0c;用于设计网络应用程序的通信模式。 一个RESTful API由以下几个关键部分组成&#xff1a; 资源&#xff08;Resour…

基于springboot实现数据资产管理系统 项目【项目源码+论文说明】

基于springboot实现数据资产管理系统演示 摘要 固定资产管理系统主要是完成对系统用户管理、资产信息管理、资产变更管理、资产用途管理、资产类别管理和资产增减管理。因为利用本系统管理员可以直接录入信息&#xff0c;修改信息&#xff0c;删除信息&#xff0c;并且若在录入…

魔众智能AI系统v2.1.0版本支持主流大模型(讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini)

支持主流大模型&#xff08;讯飞星火、文心一言、通义千问、腾讯混元、Azure、MiniMax、Gemini&#xff09; [新功能] 系统全局消息提示 UI 全新优化 [新功能] JS 库增加【ijs】类型字符串&#xff0c;支持默认可执行代码 [新功能] 分类快捷操作工具类 CategoryUtil [新功能…

RocketMQ-存储与弹性伸缩

存储与弹性伸缩 一、介绍二、存储架构图1.CommitLog2.ConsumeQueue3.IndexFile 三、消息读写流程1.写入流程1.1 获取Topic元数据1.2 消息投递1.3 消息写入 2.读取流程2.1 获取Topic元数据2.2 消息拉取2.3 消息消费 四、消息持久化1.页缓存2.刷盘2.1 同步刷盘2.2 异步刷盘 五、集…

力扣hot100:76.最小覆盖子串(滑动窗口)

本题使用滑动窗口解决&#xff0c;用right表示滑动窗口的右边界&#xff0c;left表示滑动窗口的左边界。寻找可行解&#xff0c;我们可以这样约定滑动窗口的意义&#xff1a;right指针向右移动&#xff0c;是使得滑动窗口找到可行解。left指针向右移动是为了更新窗口使得其可以…

定位算法——TDOA的Chan算法推导与Matlab实现

TDOA算法原理 TDOA(Time Difference of Arrival)——时间差到达算法&#xff0c;利用了几何数学中双曲线的特点—— 双曲线上的任意点到达两焦点的距离差是固定值。 这个距离差它天然可以抹去用户设备(UE)和基站的之间时钟误差。 P 1 C 1 c ⋅ ( t 11 Δ t ) P_1C_1 c(t_…