最小栈,设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

news2025/1/8 5:28:37

题记:

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack 类:

  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。

示例 1:

输入
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]

输出
[null,null,null,null,-3,null,0,-2]

解释
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.

提示:

  • -2 ^ 31 <= val <= 2 ^ 31 - 1
  • pop、top 和 getMin 操作总是在 非空栈 上调用
  • push, pop, top, and getMin最多被调用 3 * 104 次

题目来源:
作者:LeetCode
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xnkq37/
来源:力扣(LeetCode)

解题方法:

一:不进行最小值更新

class MinStack {
    /**
     * 数组结构实现
     */
    private $arr = null;
    private $count = 0;
    function __construct() {
        $this->arr = [];
    }

    /**
     * @param Integer $val
     * @return NULL
     * 将元素 val 推入栈中。
     */
    function push($val) {
       $this->arr[]=$val;
        $this->count++;
    }

    /**
     * @return NULL
     * 删除栈顶的元素。
     */
    function pop() {
        array_pop($this->arr);
        $this->count--;
    }

    /**
     * @return Integer
     * 获取栈顶元素
     */
    function top() {
        return $this->arr[$this->count-1];
    }

    /**
     * @return Integer
     * 检索栈中的最小元素
     */
    function getMin() {
        return min($this->arr);
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * $obj = MinStack();
 * $obj->push($val);
 * $obj->pop();
 * $ret_3 = $obj->top();
 * $ret_4 = $obj->getMin();
 */

二:最小值进行更新(官方方法)

<?php 
class MinStack {
    /**
     * 数组结构实现
     */
    function __construct() {
        $this->list = [];
        $this->minList = [];
    }

    /**
     * @param Integer $val
     * @return NULL
     * 将元素 val 推入栈中
     */
    function push($val) {
        array_push($this->list, $val);
        //对最小值数组进行判断,为空直接插入,不为空则判断大小决定是否插入
        if(count($this->minList) == 0)  
        {
            array_push($this->minList, $val);
        }else{
            if(end($this->minList) >= $val)
            {
                array_push($this->minList, $val);
            }
        }
    }

    /**
     * @return NULL
     * 删除栈顶的元素
     */
    function pop() {
        $result = array_pop($this->list);
        if($result == end($this->minList))
        {   
            //删除的栈顶元素刚好等于最小元素时,最小元素数组也要进行删除
            array_pop($this->minList);
        }
    }

    /**
     * @return Integer
     * 获取栈顶元素 
     */
    function top() {
        return end($this->list);
    }

    /**
     * @return Integer
     * 检索栈中的最小元素
     */
    function getMin() {
        return end($this->minList);
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * $obj = MinStack();
 * $obj->push($val);
 * $obj->pop();
 * $ret_3 = $obj->top();
 * $ret_4 = $obj->getMin();
 */

其他方法:主要讲思路(java)

三:使用辅助类解决

这道题让我们自定义一个栈,有push,pop,top,min四个函数。这题和官方的Stack相比就多了一个min函数。栈的实现我们可以使用链表,先来定义一个链表类

class ListNode {
    public int val;
    public int min;//最小值
    public ListNode next;

    public ListNode(int val, int min, ListNode next) {
        this.val = val;
        this.min = min;
        this.next = next;
    }
}

这里对链表的操作永远都是链表的头,假如往栈中加入3→2→5→4,画个图来看一下使用链表怎么操作的
在这里插入图片描述
代码比较简单,来看下

class MinStack {
    //链表头,相当于栈顶
    private ListNode head;

    //压栈,需要判断栈是否为空
    public void push(int x) {
        if (empty())
            head = new ListNode(x, x, null);
        else
            head = new ListNode(x, Math.min(x, head.min), head);
    }

    //出栈,相当于把链表头删除
    public void pop() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        head = head.next;
    }

    //栈顶的值也就是链表头的值
    public int top() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return head.val;
    }

    //链表中头结点保存的是整个链表最小的值,所以返回head.min也就是
    //相当于返回栈中最小的值
    public int getMin() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return head.min;
    }

    //判断栈是否为空
    private boolean empty() {
        return head == null;
    }
}

class ListNode {
    public int val;
    public int min;//最小值
    public ListNode next;

    public ListNode(int val, int min, ListNode next) {
        this.val = val;
        this.min = min;
        this.next = next;
    }
}

上面解决方式是使用一个辅助的类,实际上如果使用辅助类,我们也可以使用官方提供的栈,像下面这样。

class MinStack {
    private Stack<StackNode> stack = new Stack<>();

    //压栈
    public void push(int x) {
        if (empty()) {
            stack.push(new StackNode(x, x));
        } else {
            stack.push(new StackNode(x, Math.min(x, getMin())));
        }
    }

    //出栈
    public void pop() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        stack.pop();
    }

    public int top() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return stack.peek().val;
    }

    public int getMin() {
        if (empty())
            throw new IllegalStateException("栈为空……");
        return stack.peek().min;
    }

    //判断栈是否为空
    private boolean empty() {
        return stack.isEmpty();
    }
}

class StackNode {
    public int val;
    public int min;

    public StackNode(int val, int min) {
        this.val = val;
        this.min = min;
    }
}

四:使用单个栈解决

也可以使用官方提供的栈,当压栈的值小于栈中最小值时,先把最小值入栈,然后再把需要压栈的值入栈,最后再更新栈中最小值。如果压栈的值大于栈中最小值的时候,直接压栈,这里就以[6,2,1,4]分别入栈来看一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这是压栈的过程,出栈的时候如果出栈的值等于最小值,说明最小值已经出栈了,要更新最小值,估计直接看代码会更明白一些

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 getMin() {
        return min;
    }
}

这种方式虽然也能解决,但如果压栈的值一直递减的话,栈中会压入很多的min,实际上我们还可以在改一下,栈中压入的是需要压栈的值和最小值的差值,这样就不会压入min了,看下代码

public class MinStack {
    long min;
    Stack<Long> stack = new Stack<>();

    public void push(int x) {
        if (stack.isEmpty()) {
            stack.push(0L);
            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 getMin() {
        return (int) min;
    }
}

五:使用双栈解决(同方法二)

这个代码比较简洁,就不在说了,直接看下代码

class MinStack {
    //栈1存放的是需要压栈的值
    Stack<Integer> stack1 = new Stack<>();
    //栈2存放的是最小值
    Stack<Integer> stack2 = new Stack<>();

    public void push(int x) {
        stack1.push(x);
        if (stack2.empty() || x <= getMin())
            stack2.push(x);
    }

    public void pop() {
        //如果出栈的值等于最小值,说明栈中的最小值
        //已经出栈了,因为stack2中的栈顶元素存放的
        //就是最小值,所以stack2栈顶元素也要出栈
        if (stack1.pop() == getMin())
            stack2.pop();
    }

    public int top() {
        return stack1.peek();
    }

    public int getMin() {
        return stack2.peek();
    }
}

方法来源:
作者:数据结构和算法
链接:https://leetcode.cn/leetbook/read/top-interview-questions-easy/xnkq37/?discussion=Qgb0Ea
来源:力扣(LeetCode)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/786386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交换机和终端设备的基本配置

1 IOS访问 1.1 操作系统 所有终端设备和网络设备都需要有操作系统 (OS)。如图所示&#xff0c;操作系统中直接与计算机硬件交互的部分称为内核。与应用程序和用户连接的部分则称为外壳。用户可以使用命令行界面 (CLI) 或图形用户界面 (GUI) 与外壳交互。 使用 CLI 时&#xf…

欧姆龙以太网模块连接MCGS步骤

你是否曾经遇到过这样的问题&#xff1a;在监控PLC数据时&#xff0c;触摸屏无法与PLC通讯&#xff0c;或者PLC的通讯口被占用了&#xff1f;今天&#xff0c;我要向大家介绍一款神奇的设备——捷米特JM-ETH-CP转以太网模块&#xff0c;它能够即插即用&#xff0c;不占用PLC通讯…

被吹爆的Wi-Fi 6,究竟强在哪?

被吹爆的Wi-Fi 6&#xff0c;究竟强在哪&#xff1f; 伴随IoT技术的成熟及发展&#xff0c;Wi-Fi标准也在不断迭代升级&#xff0c;然而就实际情况来说&#xff0c;依旧有不少人仍在使用旧标准&#xff0c;比如Wi-Fi 4、Wi-Fi 5。其实WiFi的每一次升级除了速率更高&#xff0c;…

SpringCloud+Nacos集成Seata-1.7.0分布式事务

Seata是一个比较成熟的分布式事务工具&#xff0c;非常好用&#xff0c;主流的的一套&#xff0c;网上大多都是1.4版本&#xff0c;以及不完整了&#xff0c;鄙人也是找了好久才找到有个1.7版本的详细教程&#xff08;放在最后面了&#xff0c;毕竟是别人的技术&#xff0c;这里…

打造高效便捷的采购管理平台,提升企业采购效率

随着企业规模的扩大和供应链的日益复杂&#xff0c;传统的手工采购管理方式已经不能满足企业的需求。采购管理平台的出现为企业提供了一个集中、高效、便捷的采购管理工具。本文将重点探讨采购管理平台的意义与作用&#xff0c;并介绍如何打造一个高效便捷的采购管理平台。 一、…

【干货分享】如何恢复SOLIDWORKS 零件、装配体和工程图模板?

当我们卸载了SOLIDWORKS或者是购买了一台新笔记本电脑或是丢失了一直在使用的模板时&#xff0c;我们可以通过打开过去的零件、装配体和工程图文件来恢复 SOLIDWORKS 模板。 ▷ 零件模板 打开包含所需自定义属性的上一个部件。 保存零件的副本以避免对原始文件进行意外更改。…

机器学习深度学习——线性回归的从零开始实现

虽然现在的深度学习框架几乎可以自动化实现下面的工作&#xff0c;但从零开始实现可以更了解工作原理&#xff0c;方便我们自定义模型、自定义层或自定义损失函数。 import random import torch from d2l import torch as d2l线性回归的从零开始实现 生成数据集读取数据集初始…

【技术】国标GB28181视频监控平台EasyGBS视无法播放,抓包返回ICMP

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富&#xff0c;部署灵活&#xff0c;既能作为业务平台使用&#xff0c;也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视…

Ansys Speos | Presets 适合用户的预定义参数集

概述 Speos Presets 参数预置功能允许创建预定义的参数集&#xff0c;并将它们应用于新的或现有的 Speos&#xff0c;从任何 Speos 对象创建预设&#xff0c;例如光源&#xff0c;传感器&#xff0c;材料&#xff0c;仿真等&#xff0c;通过一个*.Preset 的文件定对仿真类型的配…

C++之文件操作

1.C文件操作 C中文件操作头文件:fstream。   文件类型&#xff1a;文件文件和二进制文件。 文件操作三大类&#xff1a;     ofstream 写操作     ifstream 读操作     fstream:读写操作 文件打开方式&#xff1a; 标志说明ios::in只读ios::out只写,文件不存在则…

Spring系列一:spring的安装与使用

文章目录 &#x1f49e; 官方资料&#x1f34a;Spring5下载&#x1f34a;文档介绍 &#x1f49e;Spring5&#x1f34a;内容介绍&#x1f34a;重要概念 &#x1f49e;快速入门&#x1f34a;Spring操作演示&#x1f34a;类加载路径&#x1f34a;Debug配置&#x1f34a;Spring容器…

基于Centos 7虚拟机的磁盘操作(添加磁盘、分区、格式分区、挂载)

目录 一、添加硬盘 二、查看新磁盘 三、磁盘分区 3.1新建分区 3.2 格式分区 3.3 挂载分区 3.4 永久挂载新分区 3.5 取消挂载分区 一、添加硬盘 1.在虚拟机处选择编辑虚拟机设置&#xff0c;然后选择添加 2.选择硬盘&#xff0c;然后选择下一步 3.默认即可&#xff0c;下一步…

啤酒节,燃起青岛啤酒们的“热血”

【潮汐商业评论/ 原创】 “这周五晚上我们就出发&#xff01;三年了&#xff0c;终于可以再去啤酒节畅快淋漓了&#xff01;”作为啤酒爱好者Joe兴奋道。 随着线下经济的复苏&#xff0c;疫情后的第一个盛夏正在被全国各地的“啤酒狂欢”所点燃。 7月14日晚&#xff0c;随着…

Canal安装部署与测试

文章目录 第一章 Canal概述1.1 简介1.2 工作原理1.2.1 MySQL主备复制原理1.2.2 canal 工作原理 1.3 重要版本更新说明1.4 多语言 第二章 Canal安装部署2.1 准备2.2 canal安装 第三章 Canal和Kafka整合测试注意事项 第一章 Canal概述 Github地址&#xff1a;https://github.com…

脑电信号处理与特征提取——4.脑电信号的预处理及数据分析要点(彭微微)

目录 四、脑电信号的预处理及数据分析要点 4.1 脑电基础知识回顾 4.2 伪迹 4.3 EEG预处理 4.3.1 滤波 4.3.2 重参考 4.3.3 分段和基线校正 4.3.4 坏段剔除 4.3.5 坏导剔除/插值 4.3.6 独立成分分析ICA 4.4 事件相关电位&#xff08;ERPs&#xff09; 4.4.1 如何获…

Java子类可以继承父类的所有属性吗

子类可以继承父类的所有属性吗 答案&#xff1a; 不可以&#xff0c;当然是不可以全部属性和方法都继承&#xff0c;那么哪些不可以继承&#xff1f; 最起码私有的就不可以&#xff0c;私有的属性和方法都不可以&#xff0c;其他的那就需要继续去测试了。 我用的是jdk1.8来…

Docker 的数据管理、镜像的创建

Docker 的数据管理、镜像的创建 Docker 的数据管理1&#xff0e;数据卷2&#xff0e;数据卷容器端口映射容器互联&#xff08;使用centos镜像&#xff09; Docker 镜像的创建1&#xff0e;基于现有镜像创建&#xff08;1&#xff09;首先启动一个镜像&#xff0c;在容器里做修改…

使用docker 部署自己的chatgpt

直接docker部署 docker run --name chatgpt-web -d -p 3002:3002 --env OPENAI_API_KEYyour_api_key chenzhaoyu94/chatgpt-web:latestDocker compose部署 version: 3services:app:image: chenzhaoyu94/chatgpt-web # 总是使用 latest ,更新时重新 pull 该 tag 镜像即可ports…

拆解雪花算法生成规则 | 京东物流技术团队

1 介绍 雪花算法&#xff08;Snowflake&#xff09;是一种生成分布式全局唯一 ID 的算法&#xff0c;生成的 ID 称为 Snowflake IDs 或 snowflakes。这种算法由 Twitter 创建&#xff0c;并用于推文的 ID。目前仓储平台生成 ID 是用的雪花算法修改后的版本。 雪花算法几个特性…

体验百度大模型文心千帆有感

大家好&#xff0c;我是雄雄&#xff0c;微信公众号&#xff1a;雄雄的小课堂&#xff0c;欢迎关注。 前言 近段时间来&#xff0c;各种大厂都推出了自己的大模型平台&#xff0c;有讯飞星火大模型、百度文心大模型、阿里通义千问大模型、claude、还有openai公司出产的chatgpt…