题目

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

要求

  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. iOS 原生的 UIButton 点击事件是不允许带多参数的,唯一的一个参数就是默认UIButton本身 那么我们该怎么实现传递多个参数的点击事件呢?

    UIButton *btn = // create the button objc_setAssociatedObject(btn, "firstObject", someObje ...

  2. Java原生API操作XML

    使用Java操作XML的开源框架比较多,如著名的Dom4J.JDOM等,但个人认为不管你用那个框架都要对JDK原生的API有所了解才能更得心应手的应用.本篇就来简单了解下原生的XML API. JAV ...

  3. wemall app商城源码中基于PHP的ThinkPHP惯例配置文件代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  4. ST HW2 fault & error & failure

    Software Testing 3014218128 牛菲菲 Below are two faulty programs. Each includes a test case that result ...

  5. JSP文件转换成为JAVA文件后的结构

    public final class zzz_jsp extends HttpJspBase implements JspSourceDependent{ public void _jspInit() ...

  6. ORM映射设计思想

    using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Linq; usin ...

  7. css3 的 calc()函数在布局中的使用----头部高度固定,页面正好占满一屏

    最近项目遇到一个布局需求,头部高度固定,页面需要刚好占满一屏幕. 如下示意图: 方法:使用calc .wrap{ position: relative; margin-left: 24px; marg ...

  8. 关于ORACLE通过file_id与block_id定位数据库对象遇到的问题的一点思考

    在ORACLE中,我们可以通过file_id(file#)与block_id(block#)去定位一个数据库对象(object).例如,我们在10046生成的trace文件中file#=4 block ...

  9. HTML——超文本标记语言

    HTML: 网站(站点) - 网页 1.HTML作为文件后缀名,可以把文件变为网页 2.HTML是一门编程语言的名字:超文本标记语言 3.超越了文字的范畴,除了文字还可以有图片.视频.音频.动画特效等 ...

  10. Java线程池使用和分析(一)

    线程池是可以控制线程创建.释放,并通过某种策略尝试复用线程去执行任务的一种管理框架,从而实现线程资源与任务之间的一种平衡. 以下分析基于 JDK1.7 以下是本文的目录大纲: 一.线程池架构 二.Th ...