小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进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);}
}

(友情提示:可左右滑动)

小史的疑惑

吃饭的时候,小史提出了心中埋藏已久的疑惑。

吕老师:数据结构和算法的设计是一个程序员的内功,工作时虽然用不到这么细,但是你在学习其他知识的底层原理的时候,到处都是数据结构和算法。

如何实现可以获取最小值的栈?相关推荐

  1. java获取栈最大值_实现O(1)获取最大最小值的栈----java

    实现O(1)获取最大最小值的栈和队列----java 一.如何实现包含获取最小值函数的栈 问题:定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的getMin函数.在该栈中,调用getMin ...

  2. c++ stl 获取最小值_如何在C ++ STL中找到向量的最小/最小元素?

    c++ stl 获取最小值 Given a vector and we have to minimum/smallest element using C++ STL program. 给定一个向量,我 ...

  3. Excel 2010 VBA 入门 110 获取最小值的自定义函数

    目录 例 码 使用ParamArray关键字声明数组参数 IsMissing函数 IsArray函数 函数的嵌套与递归 ​​​​​​​ 例 在VBA编程过程中,经常会使用工作表函数Min来确立某组数中 ...

  4. leetcode 155. 最小栈(常数时间获取最小值,需要维护两个栈)

    题目 思路 左神讲过的经典算法,维护两个栈: stack,用来存储数据 minStack,用来存储每个位置情况下的最小值,类似于动态规划. 每次入栈2个元素,一个是入栈的元素本身,一个是当前栈元素的最 ...

  5. T0001.数据结构面试题---栈---获取最小值

    题目 实现一个特殊的栈,在实现栈基本功能的基础上,实现返回栈中最小元素的操作. 要求: 1.pop,push,getMin操作的时间复杂度为O(1) 2.可使用现成的栈结构 GitHub源码 GitH ...

  6. 计算获取最小值和最大值

    比如,在下面的销售业绩中,统计业务员的销售业绩中最大值和最小值. 下面是业务数据: CREATE TABLE [dbo].[SalesPerformance]([ID] [int] IDENTITY( ...

  7. [jzoj 6305] 最小值 {单调栈}

    题目 解题思路 g[i]g[i]g[i]表示1到n已经划分完毕的最大价值和. O(n2)O(n^2)O(n2)方程很容易想到. 我们可以用单调栈来维护. 代码 #include<cstdio&g ...

  8. C++的STL栈实现获取栈中最小元素的成员

    实现一个获取栈中最小数据成员的函数,该栈支持如下操作: 1.push(x) : 将元素x压入栈中 2.pop() : 弹出(移除)栈顶元素 3.top() : 返回栈顶元素 4.getMin() : ...

  9. Java长见到的面试题,看你能答出几题,就知道自己有多菜了

    作者:Java3y 前言 只有光头才能变强 Redis目前还在看,今天来分享一下我在秋招看过(遇到)的一些面试题(相对比较常见的) 0.final关键字 简要说一下final关键字,final可以用来 ...

最新文章

  1. xml 和android脚本之家,Android利用Document实现xml读取和写入操作
  2. MPB:中科院生态环境中心邓晔组-环境样本中原核生物的总量测定
  3. java什么叫实例化_在JAVA中实例化的确切含义是什么
  4. 高度不定垂直居中_经典:CSS垂直居中的七种方法
  5. parse() got an unexpected keyword argument 'transport_encoding'
  6. SAP CRM 产品主数据搜索alternative ID type下拉菜单的渲染逻辑
  7. 是人是谁_谁是白鹤滩最可爱的人
  8. 香港mtmit真皮休闲商务双用时尚浮点手拿包1018 烟灰色-大号 均码【图片 价格 品牌 报价】-京东商城...
  9. 给图片添加水印效果图的函数(可以在图片上添加自己的版权和LOGO图片的水印) 【转载】...
  10. 博客园2013年5月份第2周源码发布详情
  11. 【MATLAB】MATLAB 2017A 软件安装
  12. 【Adobe Premiere Pro 2020】ps图稿导出到pr创建运动图形、pr音频录制与音频效果使用说明、pr导出为mp4格式及参数设置说明【包含其他几种常见格式】、pr去水印的4种方法说明
  13. 基于WinPcap的网络流量在线分析系统的设计与实现
  14. mysql5.6 relay.info_Relay log 导致复制启动失败
  15. 【WAF技巧拓展】————4、web应用防火墙逃逸技术(一)
  16. mysql语句占位符_sql语句中的占位符?有什么作用
  17. Windows cmd窗口的切换目录命令无法切换盘符
  18. Flash与服务器通信简介
  19. centos配置linuxptp
  20. gallery3d的源码分析——入口

热门文章

  1. 2018年创业最火热点的是什么?看到这个你可能就知道哪方面发展最热了
  2. spring的Autowired和@Resource的区别是什么
  3. 大数据助力智慧城市建设
  4. 用策略屏蔽135 139 445 3389端口+网络端口安全防护技
  5. vCenter的安装与部署
  6. topcoder srm 711 div1 -3
  7. 火狐已阻止载入混合活动内容“http://www.XXX/index.php?app=serviceac=authts=isauthurl=...
  8. android smack源码分析——接收消息以及如何解析消息
  9. 用户在购买机器之后不知如何正确保养笔记本电脑
  10. 信号处理专业名词术语