题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

思路

最初看到O(1)复杂度的时候,就想直接用一个min变量保存当前最小值,后来想到弹栈弹出的有可能是最小值,那么只能用辅助栈。

我的代码如下

class MinStack {
public Stack<Integer> minVal;//辅助栈
public Stack<Integer> s;//主栈
/** initialize your data structure here. */
public MinStack() {
minVal=new Stack<Integer>();
s=new Stack<Integer>();
} public void push(int x) {
s.push(x);
if(s.size()==1)//第一个元素入栈的时候,直接进入minVal
{
minVal.push(x);
}
else{//将当前元素与min值比较,如果小于等于min值,就入minVal栈中
int p=minVal.peek();
if(x<=p){//一定要加等号:如果有两个最小值,pop一个,还剩一个
minVal.push(x);
}
}
} public void pop() {
if(s.size()==0) ;
int k=s.pop();
int p=minVal.peek();
if(k==p){//若主栈弹出的元素是最小值就弹minVal栈
minVal.pop();
}
} public int top() {
if(s.size()==0) return -1;
return s.peek();
} public int min() {
if(minVal.size()==0) return -1;
return minVal.peek();
}
} /**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.min();
*/

改进思路

改进解法:只需要一个栈

思路

依然设置一个min变量记录当前最小值,但是当元素b(b<min)入栈时,需要做两步:

1.min入栈

2.b入栈

那么在弹栈时,若将要弹出的是当前min,就把min设置为栈顶下面的元素,然后别忘了再pop一下。(可以直接写min=s.pop(),一句话两个操作)

图解(源自LeetCode用户@数据结构和算法):





代码

class MinStack {//push方法可能会加入很多min
int min = Integer.MAX_VALUE;
Stack<Integer> stack = new Stack<>(); public void push(int x) {
//如果加入的值小于最小值,要更新最小值
if (x <= min) {
stack.push(min);
min = x;
}
stack.push(x);
} public void pop() {
//如果把最小值出栈了,就更新最小值
if (stack.pop() == min)
min = stack.pop();
} public int top() {
return stack.peek();
} public int min() {
return min;
}
}

更优改进解法:压入当前值和min的差值

思路

由于上面改进思路存在这样的不足,即如果输入的是一个递减序列,那么每次都需要将min入栈,占用空间较大;为了改进这个问题,可以不压入当前值,而是压入当前值与min的差值,pop时,若pop的是负数,说明最小值已经出栈了,重新更新最小值。

弹栈的时候分两种情况:

1.pop出来的是个负数,说明此数应该是当前最小值,直接返回min即可

2.pop出来的是个正数a,说明此数比当前min大a,返回min+a

代码

public class MinStack {
long min;
Stack<Long> stack = new Stack<>(); public void push(int x) {
if (stack.isEmpty()) {
stack.push(0L);//最初设最小值为x,所以最小值与x的差值直接是0
min = x;
} else {
//这里入栈的是入栈的值和最小值的差值,有可能为负,也有可能为正。
stack.push(x - min);
if (x < min)
min = x;
}
} public void pop() {
if (stack.isEmpty())
return;
long pop = stack.pop();
//因为入栈的是差值,当出栈的为负数的时候,说明栈中最小值已经出栈了,
//这里要重新更新最小值
if (pop < 0)
min -= pop;
} public int top() {
long top = stack.peek();
if (top > 0) {
//栈顶元素如果是正的,说明栈顶元素压栈的时候是比栈中最小值大的,根据
//top=x - min,可以计算x=top+min
return (int) (top + min);
} else {
//当栈顶元素是负数的时候,说明栈顶元素压栈的时候是比栈中最小值小的,
//而压栈完之后他会更新最小值min,所以如果在使用上面公式肯定是不行
//的。如果栈顶元素压栈的时候比最小值小,他会更新最小值,这个最小值
//就是我们要压栈的值,所以这里直接返回min就行了。
return (int) (min);
}
} public int min() {
return (int) min;
}
}

【LeetCode】剑指 Offer 30. 包含min函数的栈的更多相关文章

  1. 剑指 Offer 30. 包含min函数的栈 + 双栈实现求解栈中的最小值

    剑指 Offer 30. 包含min函数的栈 Offer_30 题目描述: 题解分析: 题目其实考察的是栈的知识,本题的目的是使用两个栈来求解最小值. 第二个栈主要用来维护第一个栈中的最小值,所以它里 ...

  2. 剑指 Offer 30. 包含min函数的栈

    剑指 Offer 30. 包含min函数的栈 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min.push 及 pop 的时间复杂度都是 O(1). 示例 ...

  3. 力扣 - 剑指 Offer 30. 包含min函数的栈

    题目 剑指 Offer 30. 包含min函数的栈 思路1 使用一个辅助栈min_stack,用来维护栈的最小的元素 每次添加元素入栈时候,data_stack和min_stack都要同时维护 dat ...

  4. 【Java】 剑指offer(30) 包含min函数的栈

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的min ...

  5. 每日一题 - 剑指 Offer 30. 包含min函数的栈

    题目信息 时间: 2019-06-24 题目链接:Leetcode tag:栈 难易程度:简单 题目描述: 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 m ...

  6. 剑指offer——30包含min函数的栈

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)).   题解: 借助辅助栈,新的数据<=f辅助栈顶时,就压入辅助栈,这样,就能保证辅 ...

  7. [剑指offer] 5. 用两个栈实现队列+[剑指offer]30. 包含min函数的栈(等同于leetcode155) +[剑指offer]31.栈的压入、弹出序列 (队列 栈)

    c++里面stack,queue的pop都是没有返回值的, vector的pop_back()也没有返回值. 思路: 队列是先进先出 , 在stack2里逆序放置stack1的元素,然后stack2. ...

  8. 《剑指offer》 包含min函数的栈

    本题来自<剑指offer> 包含min函数的栈 题目: 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 思路: 举例子让抽象问题具体 ...

  9. 【剑指Offer】包含min函数的栈 解题报告

    [剑指Offer]包含min函数的栈 解题报告 标签(空格分隔): 牛客网 题目地址:https://www.nowcoder.com/questionTerminal/beb5aa231adc45b ...

  10. Go语言实现:【剑指offer】包含min函数的栈

    该题目来源于牛客网<剑指offer>专题. 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数. 时间复杂度应为O(1). Go语言实现: var myList = ...

随机推荐

  1. KVM更改虚拟机默认存储路径

    Virt默认的虚拟机存储路径是/var/lib/libvirt/images,如下图所示 接下来我们创建一个新的存储池,用来存储新建的虚拟机.存储池的名称为vm, 路径为/home/kvm/ (/ho ...

  2. k8s集群中安装rook-ceph

    容器的持久化存储 容器的持久化存储是保存容器存储状态的重要手段,存储插件会在容器里挂载一个基于网络或者其他机制的远程数据卷,使得在容器里创建的文件,实际上是保存在远程存储服务器上,或者以分布式的方式保 ...

  3. Beats: 使用 Filebeat 进行日志json结构化 - Python

    文章转载自:https://elasticstack.blog.csdn.net/article/details/106688240

  4. 如何使用netlify部署vue应用程序

    什么是Netlify? Netlify是一个现代网站自动化系统,其JAM架构代表了现代网站的发展趋势.所谓JAM,就是指基于客户端JavaScript.可重用API和预构建Markup标记语言的三者结 ...

  5. python-D2-计算机与编程语言

    计算机五大核心 控制器 计算机的指挥系统,可以控制计算机硬件的整体运行 运算器 实现算术运算和逻辑运算 控制器和运算器结合起来就是cpu,也称为中央处理器,是整个电脑的核心. 存储器 分为两类,非永久 ...

  6. PHP + ELK实现日志记录

    一个简单的PHP 文件 效果 full.conf文件 流程: 开启logstash服务之后. 在业务代码里面操作函数写入日志.log logstash通过实践戳获取到用户的变更,取出最后一行数据,发送 ...

  7. mybatisPlus在Springboot中的使用

    文章目录 1.简介 2.支持的数据库 3.框架 4.创建一个springboot项目 4.1 .pom文件中加入依赖 4.2.yml文件的配置 4.3 .数据库脚本 4.4.实体类 4.5 .启动类添 ...

  8. 用 VS Code 搞 Qt6:信号、槽,以及QObject

    Qt 里面的信号(Signal)和槽(Slot)虽然看着像事件,但它实际上是用来在两个对象之间进行通信的.既然是通信,就会有发送者和接收者. 1.信号是发送者,触发时通过特有的关键字"emi ...

  9. 变量的复制&传递

    变量的复制 变量的类型 可以分为基本数据类型(Null.Undefined.Number.String.Boolean)和引用类型(Funtion.Object.Array) 基本数据类型是按照值访问 ...

  10. Istio(十一):向istio服务网格中引入虚拟机

    目录 一.模块概览 二.系统环境 三.虚拟机负载 3.1 虚拟机负载 3.2 单网络架构 3.3 多网络架构 3.4 Istio 中如何表示虚拟机工作负载? 四.实战:向istio Mesh中引入虚拟 ...