如何实现可以获取最小值的栈?
小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进BAT。
今天他又去BAT中的一家面试了。
简单的自我介绍后,面试官给了小史一个问题。
面试现场
题目:我现在需要实现一个栈,这个栈除了可以进行普通的push、pop操作以外,还可以进行getMin的操作,getMin方法被调用后,会返回当前栈的最小值,你会怎么做呢?你可以假设栈里面存的都是int整数。
小史熟练地把代码写了出来。
public class MinStack {private List<Integer> data = new ArrayList<Integer>();private List<Integer> mins = new ArrayList<Integer>();public void push(int num) {data.add(num);if(mins.size() == 0) {// 初始化minsmins.add(num);} else {// 辅助栈mins每次push当时最小值int min = getMin();if (num >= min) {mins.add(min);} else {mins.add(num);}}}public int pop() {// 栈空,异常,返回-1if(data.size() == 0) {return -1;}// pop时两栈同步popmins.remove(mins.size() - 1);return data.remove(data.size() - 1);}public int getMin() {// 栈空,异常,返回-1if(mins.size() == 0) {return -1;}// 返回mins栈顶元素return mins.get(mins.size() - 1);}}
(友情提示:可左右滑动)
请教大神
小史回到学校,把面试的情况和计算机学院的吕老师说了一下。
异常情况处理
吕老师:面试官已经提出了你的异常处理有点问题,当栈内为空的时候,你返回-1,但是如果用户push过-1,那么你返回-1的时候,是用户push进来的值,还是栈为空,就不得而知了。
小史咬咬牙:那就再定义一个类,里面包括一个int的data和一个boolean的isSuccess,正常情况下isSuccess是true,栈为空的话,isSuccess是false。这样就能区分开了吧?
小史突然一拍大腿:对哦,我可以用一个包装类Integer来定义返回值,如果是空,就代表栈为空就行了。它和int的区别就是它多了一个null,正好用来返回异常情况。
吕老师:嗯,越来越好,但是还是有点问题。你并没有站在使用者的角度考虑问题。使用你这个栈的人,在pop的时候,他并不知道可能返回null,如果他不做判断,后面的代码就可能抛出空指针了。
吕老师发来一个表情。
吕老师:没错,最关键的是,你显式抛出异常,如果使用者不捕获,那么编译就会报错,这样就把错误暴露在编译阶段,并且不需要和任何人商量所谓的特殊返回值了。
(码农翻身老刘注:抛出的异常应该是checked还是unchecked? 这个地方大家可以讨论下!)
算法优化
吕老师一眼看穿了小史的心思。
小史想了想:明白了,我可以在push的时候判断一下,如果比最小值还大,就不加入辅助栈。pop的时候,如果不是最小值,辅助栈就不出栈。这样一来,辅助栈就不会有大量重复元素了。
小史:push的时候进行判断,如果数值比当前最小值大,就不动mins栈了,这样mins栈中不会保存大量冗余的最小值。pop的时候同样进行判断,只有pop出的数就是当前最小值的时候,才让mins出栈。
小史:如果push一个和最小值相等的元素,还是要入mins栈。不然当这个最小值pop出去的时候。data中还会有一个最小值元素,而mins中却已经没有最小值元素了。
小史:mins栈中改存最小值在data数组中的索引。这样一来,当push了与最小值相同元素的时候,就不需要动mins栈了。而pop的时候,pop出的元素的索引如果不是mins栈顶元素,mins也不出栈。同时,获取最小值的时候,需要拿到mins栈顶元素作为索引,再去data数组中找到相应的数作为最小值。
理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了:
public class MinStack {private List<Integer> data = new ArrayList<Integer>();private List<Integer> mins = new ArrayList<Integer>();public void push(int num) {data.add(num);if(mins.size() == 0) {// 初始化minsmins.add(0);} else {// 辅助栈mins push最小值的索引int min = getMin();if (num < min) {mins.add(data.size() - 1);}}}public int pop() {// 栈空,抛出异常if(data.size() == 0) {throw new EmptyStackException();}// pop时先获取索引int popIndex = data.size() - 1;// 获取mins栈顶元素,它是最小值索引int minIndex = mins.get(mins.size() - 1);// 如果pop出去的索引就是最小值索引,mins才出栈if(popIndex == minIndex) {mins.remove(mins.size() - 1);}return data.remove(data.size() - 1);}public int getMin() {// 栈空,抛出异常if(data.size() == 0) {throw new EmptyStackException();}// 获取mins栈顶元素,它是最小值索引int minIndex = mins.get(mins.size() - 1);return data.get(minIndex);}
}
(友情提示:可左右滑动)
小史的疑惑
吃饭的时候,小史提出了心中埋藏已久的疑惑。
吕老师:数据结构和算法的设计是一个程序员的内功,工作时虽然用不到这么细,但是你在学习其他知识的底层原理的时候,到处都是数据结构和算法。
如何实现可以获取最小值的栈?相关推荐
- java获取栈最大值_实现O(1)获取最大最小值的栈----java
实现O(1)获取最大最小值的栈和队列----java 一.如何实现包含获取最小值函数的栈 问题:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的getMin函数.在该栈中,调用getMin ...
- c++ stl 获取最小值_如何在C ++ STL中找到向量的最小/最小元素?
c++ stl 获取最小值 Given a vector and we have to minimum/smallest element using C++ STL program. 给定一个向量,我 ...
- Excel 2010 VBA 入门 110 获取最小值的自定义函数
目录 例 码 使用ParamArray关键字声明数组参数 IsMissing函数 IsArray函数 函数的嵌套与递归 例 在VBA编程过程中,经常会使用工作表函数Min来确立某组数中 ...
- leetcode 155. 最小栈(常数时间获取最小值,需要维护两个栈)
题目 思路 左神讲过的经典算法,维护两个栈: stack,用来存储数据 minStack,用来存储每个位置情况下的最小值,类似于动态规划. 每次入栈2个元素,一个是入栈的元素本身,一个是当前栈元素的最 ...
- T0001.数据结构面试题---栈---获取最小值
题目 实现一个特殊的栈,在实现栈基本功能的基础上,实现返回栈中最小元素的操作. 要求: 1.pop,push,getMin操作的时间复杂度为O(1) 2.可使用现成的栈结构 GitHub源码 GitH ...
- 计算获取最小值和最大值
比如,在下面的销售业绩中,统计业务员的销售业绩中最大值和最小值. 下面是业务数据: CREATE TABLE [dbo].[SalesPerformance]([ID] [int] IDENTITY( ...
- [jzoj 6305] 最小值 {单调栈}
题目 解题思路 g[i]g[i]g[i]表示1到n已经划分完毕的最大价值和. O(n2)O(n^2)O(n2)方程很容易想到. 我们可以用单调栈来维护. 代码 #include<cstdio&g ...
- C++的STL栈实现获取栈中最小元素的成员
实现一个获取栈中最小数据成员的函数,该栈支持如下操作: 1.push(x) : 将元素x压入栈中 2.pop() : 弹出(移除)栈顶元素 3.top() : 返回栈顶元素 4.getMin() : ...
- Java长见到的面试题,看你能答出几题,就知道自己有多菜了
作者:Java3y 前言 只有光头才能变强 Redis目前还在看,今天来分享一下我在秋招看过(遇到)的一些面试题(相对比较常见的) 0.final关键字 简要说一下final关键字,final可以用来 ...
最新文章
- xml 和android脚本之家,Android利用Document实现xml读取和写入操作
- MPB:中科院生态环境中心邓晔组-环境样本中原核生物的总量测定
- java什么叫实例化_在JAVA中实例化的确切含义是什么
- 高度不定垂直居中_经典:CSS垂直居中的七种方法
- parse() got an unexpected keyword argument 'transport_encoding'
- SAP CRM 产品主数据搜索alternative ID type下拉菜单的渲染逻辑
- 是人是谁_谁是白鹤滩最可爱的人
- 香港mtmit真皮休闲商务双用时尚浮点手拿包1018 烟灰色-大号 均码【图片 价格 品牌 报价】-京东商城...
- 给图片添加水印效果图的函数(可以在图片上添加自己的版权和LOGO图片的水印) 【转载】...
- 博客园2013年5月份第2周源码发布详情
- 【MATLAB】MATLAB 2017A 软件安装
- 【Adobe Premiere Pro 2020】ps图稿导出到pr创建运动图形、pr音频录制与音频效果使用说明、pr导出为mp4格式及参数设置说明【包含其他几种常见格式】、pr去水印的4种方法说明
- 基于WinPcap的网络流量在线分析系统的设计与实现
- mysql5.6 relay.info_Relay log 导致复制启动失败
- 【WAF技巧拓展】————4、web应用防火墙逃逸技术(一)
- mysql语句占位符_sql语句中的占位符?有什么作用
- Windows cmd窗口的切换目录命令无法切换盘符
- Flash与服务器通信简介
- centos配置linuxptp
- gallery3d的源码分析——入口
热门文章
- 2018年创业最火热点的是什么?看到这个你可能就知道哪方面发展最热了
- spring的Autowired和@Resource的区别是什么
- 大数据助力智慧城市建设
- 用策略屏蔽135 139 445 3389端口+网络端口安全防护技
- vCenter的安装与部署
- topcoder srm 711 div1 -3
- 火狐已阻止载入混合活动内容“http://www.XXX/index.php?app=serviceac=authts=isauthurl=...
- android smack源码分析——接收消息以及如何解析消息
- 用户在购买机器之后不知如何正确保养笔记本电脑
- 信号处理专业名词术语