题目

实现一个特殊的栈,在实现栈的基本功能的基础上,在实现返回栈中最小元素的操作。

要求

  1. pop、push、getMin操作的时间复杂度都是O(1).
  2. 设计的栈类型可以使用现成的栈结构。

解答

在设计上我们使用两个栈,一个栈用来保存当前栈中的元素,其功能和一个正常的栈没有区别,这个栈记为stackData;另一个栈用于保存每一步的最小值,这个栈记为stackMin。具体实现的方式有两种。

第一种

压入数据规则

假设当前数据为newNum,现将其压入stackData。然后判断stackMin是否为空:

  • 如果为空,则newNum也压入stackMin。
  • 如果不为空,则比较newNum和stackMin的栈顶元素中哪一个更小:
  • 如果newNum更小或两者相等,则newNum也压入stackMin;
  • 如果stackMin中的栈顶元素小,则stackMin不压如任何内容。

举例:一次压入3、4、5、1、2、1的过程中,stackData和stackMin的变化下图:

数据弹出规则

  先在stackData中弹出栈顶元素,记为value。然后比较当前stackMin的栈顶元素和value哪一个更小。

  通过上文提到的压入规则可知,stackMin中存在的元素是从栈底到栈顶逐渐变小的,stackMin栈顶的元素既是stackMin栈的最小值,也是当前stackData栈中的最小值。所以不会出现value比stackMin的栈顶元素更小的情况,value只可能大于或等于stackMin的栈顶的元素。

  当value等于stackMin的栈顶元素时,stackMin弹出栈顶元素;当value大于stackMin的栈顶元素时,stackMin不弹出栈顶元素;返回false。

  很显然可以看出,压入与弹出规则是对应的。

查询当前栈中的最小值操作

  由上文的压入数据规则和弹出数据规则可知,stackMin始终记录着stackData中的最小值,所以,stackMin栈顶元素始终是当前stackData中的最小值。

下面看一下代码:

public class MyStack1 {

    private Stack<Integer> stackData;
private Stack<Integer> stackMin; public MyStack1(){
stackData = new Stack<>();
stackMin = new Stack<>();
} public void push(int newNum){
if(this.stackMin.isEmpty()){
this.stackMin.push(newNum);
}else if(newNum<=this.getMin()){
this.stackMin.push(newNum);
}
this.stackData.push(newNum);
} public int pop(){
if(this.stackData.isEmpty()){
throw new RuntimeException("Your stack is empty.");
}
int value = this.stackData.pop();
if(value==this.getMin()){
this.stackMin.pop();
}
return value;
} public int getMin(){
if(this.stackMin.isEmpty()){
throw new RuntimeException("Your stack is empty");
}
return this.stackMin.peek();
}
}

第二种

压入数据的规则

假设当前数据为newNum,现将其压入stackData、然后判断stackMin是否为空。

如果为空,则newNum也压入stackMin;如果不为空,则比较newNum和stackMin的栈顶元素中哪一个更小;

如果newNum更小或者两者相等,则newNum也压入stackMin;如果stackMin中栈顶元素小,则吧stackMin的栈顶元素重复压入stackMin,即在栈顶元素上再压入一个栈顶元素。

举例:一次压入3、4、5、1、2、1的过程,stackData和stackMin的变化如下图。

弹出数据规则

在stackData中弹出数据,弹出数据记为value;弹出stackMin中的栈顶;返回value。很明显可以看出,压入与弹出规则是对应的。

查询当前栈中的最小值操作

由上文的压入数据规则和弹出数据规则可知,stackMin始终记录着stackData中的最小值,所以stackMin的栈顶元素始终是当前stackData中的最小值。

方案二的代码实现如MyStack2类所示:

public class MyStack2 {
private Stack<Integer> stackData;
private Stack<Integer> stackMin; public MyStack2(){
stackData = new Stack<>();
stackMin = new Stack<>();
} public void push(int newNum){
if(this.stackMin.isEmpty()){
this.stackMin.push(newNum);
}else if(newNum<this.getMin()){
this.stackMin.push(newNum);
}else{
int newMin = this.stackMin.peek();
this.stackMin.push(newMin);
}
this.stackData.push(newNum);
} public int pop(){
if(this.stackData.isEmpty()){
throw new RuntimeException("Your stack is empty.");
}
this.stackMin.pop(); return this.stackData.pop();
} public int getMin(){
if(this.stackMin.isEmpty()){
throw new RuntimeException("Your stack is empty");
}
return this.stackMin.peek();
}
}

方案一和方案二其实都是stackMin栈保存着stackData每一步的最小值。共同是所有操作的时间复杂度都为O(1)、空间复杂度都是O(n)。区别是:方案一种stackMin压入时稍省空间,但是弹出操作稍费时间;方案二中stackMin压入时稍费空间,但是弹出操作稍省时间。

栈实现getMin的更多相关文章

  1. 栈 · 有getMin功能的栈O(1)

    题面 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中的最小元素的操作. 要求 pop(), push(), getMin()时间复杂度都是O(1) 思路 1.准备两个栈,数据栈+最小元素 ...

  2. c++后台开发面试常见知识点总结(六)算法手写

    链表倒转  leetcode-206 连续子数组最大和问题(和最大的连续子序列的和)   leetcode-53 输出字符串中最长的回文子串长度?  leetcode-5 一个字符串,求最长无重复子串 ...

  3. 算法与数据结构题目的 PHP 实现:栈和队列 设计一个有 getMin 功能的栈

    刚入手了一本<程序员代码面试指南>,书中题目的代码都是 Java 实现的,琢磨着把这些代码用 PHP 敲一遍,加深印象. 题目:设计一个有 getMin 功能的栈 —— 实现一个特殊的栈, ...

  4. 实现带有getMin的栈

    题目 实现一个特殊的栈,在实现栈的基础上,再实现返回栈中最小的元素的操作. 要求 pop.push.getMin的时间复杂度是O(1) 可以使用现成的栈类型 思路 如下图所示,在栈结构中,每次pop的 ...

  5. 设计一个有getMin功能的栈

    [说明]: 本文是左程云老师所著的<程序员面试代码指南>第一章中“设计一个有getMin功能的栈”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解析说明 ...

  6. 设计一个有getMin功能的栈(2)

    题目: 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作. 要求: 1.pop.push.getMin操作的时间复杂度都是O(1) 2.设计的栈类型可以输用现成的栈结构 解答 ...

  7. 设计一个有getMin功能的栈(1)

    题目: 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作. 要求: 1.pop.push.getMin操作的时间复杂度都是O(1) 2.设计的栈类型可以输用现成的栈结构 解答 ...

  8. 设计一个带有getmin功能的栈,保证时间复杂度在O(1)

    2017-06-22  20:56:10 需要得到最小值,最简单的思路就是遍历一遍求出最小值.但是这样的时间复杂度会是O(n),不满足O(1)的要求.于是想到在建立一个栈来保存最小值. 具体操作是建立 ...

  9. 常见面试算法题JS实现-设计一个有getMin功能的栈

    前言: 已经确定工作了-下周一正式入职,按理说应该是可以好好浪荡一周的,但是内心总是不安,总觉得自己这个水平真的太菜了,还是趁着现在有自己的时间,赶紧多看看书,多学习学习吧orz所以把之前校招买的书, ...

随机推荐

  1. Java对象序列化的使用和定制

    序列化的概念及使用场合 序列化就是把对象转化为字节序列并持久化保存,可以保存在内存中.磁盘文件系统,甚至通过网络传递,并能够在以后将这个字节序列完全恢复为原来的对象. 对象序列化的概念引入Java是为 ...

  2. 浅谈Java的集合体系

    集合体系框架图 集合接口 Java集合类库将接口(interface)与实现(implementation)分离,如上图,Set是一个集合接口,而HashSet与TreeSet都是实现了Set接口的子 ...

  3. 【2-23】分支语句(switch…case)及循环语句

    Switch-case分支语句与if语句作用相同,但需将情况都罗列出比较麻烦所以不常用. 其基本结构是: Switch(一个变量值) { Case 值1:要执行的代码段:break; Case 值2: ...

  4. 【2017-03-10】Tsql语句基础、条件,高级查询

    一.语句基础 1.创建数据库:create database 数据库名(不能汉字,不能数字.符号开头) 2.删除数据库:drop database 数据库名 3.选用数据库:use 数据库名 4.创建 ...

  5. ThinkPhp框架:有条件的数据库查询、tp框架的其他知识

    上一篇的随笔写的是基本操作,现在可以做一些高级操作,例如有条件的查询数据,有分页的条件查询数据 一.一个条件的查询数据 查询数据自然是先要显示出数据,然后根据条件进行查询数据 (1)显示出表的数据 这 ...

  6. 3409: [Usaco2009 Oct]Barn Echoes 牛棚回声

    3409: [Usaco2009 Oct]Barn Echoes 牛棚回声 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 57  Solved: 47[ ...

  7. 模态Model视图Push下一个视图(混合跳转)

    来自: http://www.cnblogs.com/dingding3w/p/6222626.html 如果没有UINavigationController导航栏页面之间切换是不能实现Push操作的 ...

  8. 分享小知识:善用Group By排序

    以下列举了公用表/临时表/聚合函数三个因素为例子(覆盖索引因素除外,有利用此类索引都会以索引顺序)  环境: Microsoft SQL Server 2014 (SP1-GDR) (KB319472 ...

  9. ASP.NET Core MVC 源码学习:Routing 路由

    前言 最近打算抽时间看一下 ASP.NET Core MVC 的源码,特此把自己学习到的内容记录下来,也算是做个笔记吧. 路由作为 MVC 的基本部分,所以在学习 MVC 的其他源码之前还是先学习一下 ...

  10. layer插件

    最近在做公司的官网,其中有用到layer这款插件,以前没有接触过,不过学下来觉得好用好学.下面分享一下我的学习心得. layer是web弹出层组件.在官网下载好layer后,把他部署到你的项目文件中( ...