栈系列之 最小栈的实现

2023-11-05

算法专题导航页面


【算法专题 - 栈】

  1. 栈系列之 栈排序
  2. 栈系列之 最小栈的实现
  3. 栈系列之 用栈实现队列
  4. 栈系列之 递归实现一个栈的逆序

【题目】
  设计一个栈,其拥有常规的入栈、出栈操作外,需要额外具备获取最小元素的功能

【其他限制】
  获取最小元素功能的时间复杂度O(1)

【图示】
  给定一个无序整数序列: 3, 8, 5, 6, 9, 1, 0, 2.
在这里插入图片描述
【分析】
1. 是否可以利用众所周知的栈结构及其入栈、出栈特性
    答案是肯定的,现在的问题在于单靠一个栈结构是无法实现获取最小元素功能。
2. 算法时间复杂度和空间复杂度衡量?
    题目要求的O(1)时间复杂度已是最优,同时也表明该算法需要采用空间换时间策略。在O(1)时间复杂度获取一个序列极值的数据结构:有序数组,哈希表,最大(小)堆。
    我们可以尝试构造上面提及的三种数据结构来实现最小元素获取功能,但这个“构造的过程”明显会引入额外的时间复杂度。

【解决方案】
    基于上述两方面分析,结合元素进栈/出栈操作,这里我们尝试采用一个辅助栈(MinStack)配合原始栈(MainStack)实现算法需要的新特性。其时间复杂度为O(1),空间复杂度为O(n)。
    一个元素压入原始栈时,条件性压入辅助栈(目的是保存当前原始栈中值最小的元素);元素弹出原始栈时,同样需要条件性弹出辅助栈的栈顶元素(目的是确保辅助栈的栈顶元素当前原始栈中值最小的元素)。

  • 元素进栈操作
  1. 辅助栈MinStack为空。
    元素首先压入原始栈MainStack,而后直接压入辅助栈MinStack。
  2. 辅助栈MinStack非空。
    元素首先压入原始栈MainStack,而后判断该元素是否需要压入辅助栈MinStack。
    此时分以下两种情况:
        a. 新入栈元素大于等于辅助栈栈顶元素。该元素不会被压入辅助栈。
        b. 新入栈元素小于辅助栈栈顶元素。该元素需要被压入辅助栈。
    此处有一个细节需要注意:入栈操作过程中及完成后,辅助栈中元素自底向上是一个递减序列。
    具体分析请看下面图解:
    (1) 元素3压入原始栈,此时辅助栈为空,故需要同时将其压入辅助栈。后续元素8, 5, 6, 9压入原始栈时,辅助栈不会有任何入栈操作。
    在这里插入图片描述
    (2) 元素1压入原始栈,此时辅助栈非空。元素1小于辅助栈栈顶元素3,故元素1需要同时压入辅助栈。
    在这里插入图片描述
    (3) 元素0压入原始栈,此时辅助栈亦非空。元素0小于辅助栈栈顶元素1,故元素0需要同时压入辅助栈。
    在这里插入图片描述
    最后,尾元素2压入原始栈,因其大于辅助栈栈顶元素0,故无需压入辅助栈。至此算法的入栈操作完成。
  • 元素出栈操作
    出栈操作相对简单:首先弹出原始栈的栈顶元素,当该栈顶元素等于辅助栈的栈顶元素时,弹出辅助栈的栈顶元素,以此来保证辅助栈的栈顶元素永远是原始栈当前元素中最小的元素。

【代码实现 - Java 精简版】

/*
 * DESC:
 * Java
 * A class implements function that can obtain the least element
*/ 
public class EnhancedStack {
    private Stack<Integer> mainStack;
    private Stack<Integer> minStack;
    public EnhancedStack() {
        this.mainStack = new Stack<Integer>();
        this.minStack = new Stack<Integer>();
    }

    // Push an element to stack EnhancedStack
    public void pushAction(int element) {
        this.mainStack.push(element);
        if (this.minStack.isEmpty() || (!this.minStack.isEmpty() && element < this.minStack.peek()))
            this.minStack.push(element)
    }

    // Pop an element from stack EnhancedStack
    public int popAction() {
        if (this.mainStack.IsEmpty())
            throw new RuntimeException("The stack is empty, please check!");
        int val = this.mainStack.pop();
        if (val == this.minStack.peek())
            this.minStack.pop();
        return val;
    }
    // Get the least element of current stack EnhancedStack
    public int getMinElement() {
        if (this.minStack.IsEmpty())
            thrown new RuntimeException("The stack is empty, please check!");
        return this.minStack.peek();
    }
}

【代码实现 - CPP 可运行版】

[输入描述]
第一行输入一个整数N,表示对栈进行的操作总数。
下面N行每行输入一个字符串S,表示操作的种类。
如果S为"push",则后面还有一个整数X表示向栈里压入整数X。
如果S为"pop",则表示弹出栈顶操作。
如果S为"getMin",则表示询问当前栈中的最小元素是多少。

[输出描述]
对于每个getMin操作,输出一行表示当前栈中的最小元素是多少。
示例1
输入:

6
push 3
push 2
push 1
getMin
pop
getMin

输出:

1
2
[备注]
1<=N<=1000000
-1000000<=X<=1000000
//C++11(clang++ 3.9)

#include<iostream>
#include<stack>

using namespace std;

/*
* DESC:
* A enhanced stack that can get its minal element easily
*/
class EnhancedStack{
public:
   EnhancedStack(){}
   ~EnhancedStack(){}

   void pushAction(int element) {
       // push new element to the mainStack each time, but do the same to minStack conditionity
       mainStack.push(element);
       if (minStack.empty()|| element < minStack.top()) {
           minStack.push(element);
       } else {
           // push the top element to itself, this step will keep the size of two stacks' elements algin
           minStack.push(minStack.top());
       }
   }

   void popAction() {
       if (mainStack.empty()) {
           throw out_of_range("The stack is empty, please check!\n");
       } else {
           // based on the pushAction operation, here we just pop for both stacks simply 
           mainStack.pop();
           minStack.pop();
       }
   }

   int getMinElement() {
       if (minStack.empty()) {
           throw out_of_range("The stack is empty, please check!\n");
       } else {
           return minStack.top();
       }
   }

private:
   stack<int> mainStack;
   stack<int> minStack;
};


int main() {
   // new a EnhancedStack object
   EnhancedStack eStack;
   
   // define vars for input
   int stackSize = 0;
   string cmdStr;
   int element = 0;
   
   cin >> stackSize;
   while(stackSize --) {
       cin >> cmdStr;
       if ("push" == cmdStr) {
           cin >> element;
           eStack.pushAction(element);
       } else if ("getMin" == cmdStr) {
           cout << eStack.getMinElement() <<endl;
       } else {
           eStack.popAction();
       }
   }
   return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

栈系列之 最小栈的实现 的相关文章

  • 逆序栈(递归⚠)

    给你一个栈 请逆序这个栈 不能申请额外的数据结构 只能使用递归求解 题解 这道题难点就在于无法申请额外数据结构 可以用两个递归函数实现 第一个递归函数GetBottom 主要用途是将栈底的数据出栈 并返回该数据的值 所以我们可以使用递归让栈
  • 栈系列之 最小栈的实现

    算法专题导航页面 算法专题 栈 栈系列之 栈排序 栈系列之 最小栈的实现 栈系列之 用栈实现队列 栈系列之 递归实现一个栈的逆序 题目 设计一个栈 其拥有常规的入栈 出栈操作外 需要额外具备获取最小元素的功能 其他限制 获取最小元素功能的时
  • 算法与数据结构_栈

    栈 一 什么是栈 特点总结为先进后出 后进先出 就是 First In Last Out FILO 这就是典型的 栈 结构 从其操作特性来看 栈是一种 操作受限 的线性表 它只允许从一端进行数据的插入与移除 二 既然栈不如链表 数组灵活 为
  • Java中的内存分配

    Java把内存划分成两种 一种是栈内存 一种是堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配 当在一段代码块定义一个变量时 Java就在栈中为这个变量分配内存空间 当超过变量的作用域后 Java会自动释放掉为
  • 两个栈实现一个队列(图解),一看就懂

    两个栈实现一个队列 要想实现此方法 我们现需要了解一下什么是栈和队列 栈 栈 Stack是一种只能在一端进行插入或删除操作的线性表 表中允许进行插入 删除操作的一端称为栈顶 Top 栈顶的当前位置是动态的 栈顶的当前位置是由一个称为栈顶指针
  • 面试经典(24)--二叉搜索树和双向链表

    题目描述 输入一棵二叉搜索树 将该二叉搜索树转换成一个排序的双向链表 算法分析 使用后续遍历方法 从10节点开始分析 只要左子树返回最大节点 右子树返回最小节点即可 正常递归无法判定当前是左子树还是右子树 所以参数要假如bool值判定左右子
  • 栈、队列的基本概念和操作

    目录 一 栈 stack 了解 1 1 栈的实现和操作 二 队列 queue 了解 2 1 队列的实现与操作 2 2 双端队列 一 栈 stack 了解 概念 栈 stack 有些地方称为堆栈 是一种容器 可存入数据元素 访问元素 删除元素
  • Java实现二叉树的遍历(递归和非递归)

    现有一颗如下图所示的二叉树 一 基本概念 1 先序遍历 深度优先遍历 前 中 后这三个词是针对根节点的访问顺序而言的 先访问根结点 再访问左子结点 最后访问右子结点 图中的二叉树的先序遍历的顺序是1 2 4 8 9 5 3 6 7 2 中序
  • C++语法基础之栈和队列

    栈 头文件 lt stack gt 实例化 stack在内部默认使用std deque存储数据 但是可以指定使用vector或者list存储数据 示例 std stack
  • 数据结构学习——顺序栈和链式栈的简单实现和解析(C语言版)

    数据结构 栈的简单解析和实现 一 概念 二 入栈 push 三 出栈 pop 四 顺序栈简单实现 1 进栈操作 2 出栈操作 一 概念 本篇所讲解的栈和队列属于逻辑结构上的划分 逻辑结构分为线性结构 非线性结构 线性结构 有且仅有一个开始节
  • 有趣的数据结构算法10——后缀表达式(PRN)介绍及利用栈计算后缀表达式的结果

    有趣的数据结构算法10 后缀表达式 PRN 介绍及利用栈计算后缀表达式的结果 解题思路 实现代码 GITHUB下载连接 在前一天已经利用栈完成2进制到8进制的转换 但是栈的应用方面还有很多 本次我将讲解如何计算后缀表达式的结果 解题思路 后
  • 出栈的合法性检测

    对于一个给定的入栈顺序 可能的出栈顺序会有很多 但是肯定都要遵循栈 后进先出 的特点 那么怎么进行合法性检测呢 算法思想如下 定义变量InIndex标记入栈序列的当前位置 定义OutIndex标记出栈序列的当前位置 对InIndex和Out
  • Leetcode题解——30. 包含min函数的栈(辅助栈思想)

    题目地址 剑指 Offer 30 包含min函数的栈 力扣 LeetCode 目录 一 算法思想 二 代码实现 三 拓展思考 首先说结论 这道题虽然难度不大 但是算法思想很重要 是辅助栈应用的生动实例 所以 这里小编不再重点将代码 而是讲思
  • 数据结构-线性表之堆栈

    什么是栈 是一种数据结构 能够实现后进先出的一种业务场景 即栈中的元素被处理时 按后进先出的顺序进行 所以栈又叫做后进先出表 LIFO 例子 生活中的叠放在厨房桌子上的碗就是一种栈结构 放的时候只能把碗放在最上面 取的时候只能从最上面开始取
  • 【C++编程基础】AOJ (C++ Programming II)—2-A-stack

    2 A stack 题目 stack Stack is a container of elements that are inserted and deleted according to LIFO Last In First Out Fo
  • 数据结构之 栈(C语言实现)

    数据结构之 栈 C语言实现 1 栈的模型 栈 stack 是限制插入和删除只能在一个位置上进行的表 该位置是表的末端 叫做栈的顶 top 对栈的基本操作有push 进栈 和pop 出栈 前者相当于插入 后者则是删除最后插入的元素 最后插入的
  • 数据结构----链式栈

    目录 前言 链式栈 操作方式 1 存储结构 2 初始化 3 创建节点 4 判断是否满栈 5 判断是否空栈 6 入栈 7 出栈 8 获取栈顶元素 9 遍历栈 10 清空栈 完整代码 前言 前面我们学习过了数组栈的相关方法 链接 线性表 栈 栈
  • 用栈来判断括号匹配问题

    用栈实现 输入一行符号 以 结束 判断其中的括号是否匹配 括号包括 lt gt 如果匹配 输出 right 如果不匹配 给出错误提示 包括 1 对称符号都匹配 输出 right 2 处理到某个符号时不匹配了 输出 The character
  • 【数据结构】详解栈的应用之表达式求值

    首先明白 前缀表达式 符号在前 如 3456 中缀表达式 符号在中间 如 3 4 5 6 后缀表达式 符号在最后 如34 5 6 后缀表达式不出现括号 中缀表达式转后缀表达式的方法 1 遇到数字 直接输出 添加到后缀表达式中 2 栈为空时
  • 使用c++超详细解释数据结构中的顺序栈和链栈

    在C 中 栈 Stack 是一种数据结构 它可以用来存储数据 并支持两种基本操作 压入 Push 和弹出 Pop 栈的特点是后进先出 Last In First Out LIFO 也就是最后压入的元素最先弹出 栈可以用数组或链表等数据结构来

随机推荐

  • 左手坐标系和右手坐标系

    转自 https blog csdn net xiaoluoshan article details 53384103 基本的数学知识 左手坐标系和右手坐标系 这些对于搞图像开发或者游戏开发的朋友来说 应该是很基础的东西 不过对于大部分人来
  • VB mschart控件的使用

    一 先看个小例子 Private Sub Form Load Dim MyData 20 1 As Double x轴坐标值 Y轴坐标值 MyData 0 0 0 MyData 0 1 180 本句代表了 第一点数据的X轴坐标为0 Y轴坐标
  • UCOS2的文件目录

    想着闲着也是闲着 把之前学习ucos2源码的笔记整理一下 复盘一次 总结内容将其写为博客作为学习的输出 一 为什么要学RTOS或者IOTOS 我在大一时 开始进入实验室接触单片机 摸爬滚打的参加了几次比赛 也因此入了嵌入式的坑 大三时开始思
  • 一位年薪40W的测试被开除,回怼的一番话,令人沉思

    一位年薪40W测试工程师被开除回怼道 反正我有技术 在哪不一样 一技傍身 万事不愁 当我们掌握了一技之长后 在职场上说话就硬气了许多 不用担心被炒 反过来还可以炒了老板 这一点在码农界特别明显 许多测试人在辞职时 都有一种心态 烂公司 烂领
  • 学习第一天const

    constant 指针与const const char a 指向const对象的指针或者说指向常量的指针 char const a 同上 char const a 指向类型对象的const指针 或者说常指针 const指针 const c
  • ORACLE集群管理-19c RAC ipv6+IPV4双栈配置实战

    关于IPV6支持问题 单实例环境要支持IPV6 数据库版本至少11 2 0 4版本 其实从linux7开始系统默认开启ipv6 怎么确认ipv6是否开启呢 下面介绍两种常见的方法 1 通过查看网卡属性确定 ifconfig a 命令输出有
  • Vue计算两个datetime共多少天

    假如starttime和endtime都是YYYY MM DD HH mm ss类型 将选择器的默认时间格式 object 转换成时间戳 开始时间减去结束时间 时间戳的形式进行运算 s然后转换成天数 通过toFixed函数保留两位小数 th
  • c语言中swap的意思,C语言中swap的作用和用法?

    慕村225694 swap函数一般是一个程序员自定义函数 通常是实现两个变量数值的交换 比如123int a 2 int b 3 swap a b 一般用到变量数值交换 交换后a 3 b 2 实现的方法多种多样 比如下面几种写法 1 通过使
  • Python——类的方法重写、property、运算符重载

    1 super 函数 主要是用来调用父类的方法 在子类中调用父类的方法时进行使用 2 私有方法 私有属性 1 定义方法 在类的内部 使用def关键字可以为类定义一个方法 与一般函数定义不同 类方法必须包含参数self 且为第一个参数 2 私
  • ubuntu搭建vpn步骤

    1 搭建环境 系统 Ubuntu 18 04 4 LTS Bionic Beaver 位置 轻量应用云服务器 2 安装软件 Sudo apt get update Sudo apt get install pptpd Sudo apt ge
  • 【ESP8266】关于调试fatal exception/自动重启的一些经验分享

    本人小白一枚 最近在捣鼓ESP8266的NONOS SDK开发 本来已经写好了一个工程测试基本功能也没什么问题了 但是发现了一个很严重的问题 就是每次一跑上40来分钟的时候 就会宕机重启 自动重启 真是奇了个怪了 本来这也没啥 但出于对稳定
  • 关闭 Ubuntu 中的关机/重启确认的小技巧

    导读 对于 Ubuntu 新手来说 有很多新东西要学 但是网上很多教程不是针对新手的 在这里 我们不走寻常路 不能说全部的教程都是为初学者准备 但至少大部分是 关闭 Ubuntu 中的关机 重启确认 这篇文章也是一篇新手教程 并且展示如何在
  • Android常用控件之悬浮窗

    悬浮窗可以显示在所有应用程序之上 不管在PC机还是Android设备上都有这个 最常见的是360的 加速球 来看下在Android设备上的效果 程序的目录结构如下图 创建Activity后启动Service就关闭 java view pla
  • 基于cordova打包RPGMAKERMV 安卓app

    基于cordova打包RPGMAKERMV 安卓app 1 RPGMakerMV部分 部署出网页项目 2 node部分 https nodejs org en 上下载node左边稳定版 右边是包含最新特性的版本 这是目前的版本可能不一样 设
  • 刷题之图像渲染

    有一幅以二维整数数组表示的图画 每一个整数表示该图画的像素值大小 数值在 0 到 65535 之间 给你一个坐标 sr sc 表示图像渲染开始的像素值 行 列 和一个新的颜色值 newColor 让你重新上色这幅图像 为了完成上色工作 从初
  • Verilog基本语法之循环语句(六)

    循环语句分为以下4种 for语句 通过三个步骤来决定语句的循环执行 1 给控制循环次数的变量赋初值 2 判定循环执行条件 若为假则跳出循环 若为真 则执行指定语句后 转到第三步 3 修改循环变量的值 返回第二步 repeat 连续执行一条语
  • qt 调节win声音版本大小

    QT4 情况下 运行的 会出错 目前暂时没有办法解决在 win下调节音量大小问题 在这里插入代码片 参考资料 QT 对window系统下音量的设置和获取 还有个很好贴子 没有找到
  • vim入门了

    自从上次搞定代码折叠之后 仿佛vim真的入门了 今天又看了一些内容 会复制 粘贴 查找了 更加的感觉入门了 值得庆贺 2012 5 3
  • JZOJ 幽幽子与森林

    题目大意 迷途竹林可以看成是一个n个点的森林 幽幽子定义dis u v 为u到v路径上的边的数量 若u和v不连通则为m 她定义整个森林的危险度为 为了去拜访永琳师匠 幽幽子需要提前知道迷途竹林的危险度 但迷途竹林的形态是时刻变化着的 所以幽
  • 栈系列之 最小栈的实现

    算法专题导航页面 算法专题 栈 栈系列之 栈排序 栈系列之 最小栈的实现 栈系列之 用栈实现队列 栈系列之 递归实现一个栈的逆序 题目 设计一个栈 其拥有常规的入栈 出栈操作外 需要额外具备获取最小元素的功能 其他限制 获取最小元素功能的时