当前位置: 首页 > news >正文

力扣(最小栈)

解析 LeetCode 155. 最小栈:基于链表的高效实现

一、题目分析

在这里插入图片描述

(一)功能需求

实现 MinStack 类,包含以下操作:

  • MinStack():初始化栈对象。
  • void push(int val):将元素压入栈。
  • void pop():移除栈顶元素。
  • int top():获取栈顶元素的值。
  • int getMin():获取栈中的最小元素,要求时间复杂度为 O(1) 。

(二)核心挑战

如何在执行常规栈操作的同时,高效维护最小元素。若每次调用 getMin 都遍历栈查找,时间复杂度会达到 O(n) ,无法满足题目要求。因此,需在栈的结构设计上做文章,让最小元素的获取无需遍历。

二、算法思想:链表节点存储“值 + 当前最小值”

(一)链表节点的设计

使用自定义的 Node 类,每个节点存储三个信息:

  • val:当前节点存储的元素值。
  • min:以当前节点为栈顶时,栈中的最小元素值。
  • next:指向下一个节点的指针(构建链表结构 )。

这样,每个节点在入栈时,就记录了从栈底到当前节点的最小元素,后续获取最小元素时,直接访问栈顶节点的 min 属性即可,时间复杂度为 O(1) 。

(二)栈的操作逻辑

  • 初始化:用一个哨兵节点(head )简化链表操作,其 val 可设为任意值(如示例中的 666 ),min 设为 Integer.MAX_VALUE(不影响实际逻辑 ),next 初始为 null
  • push 操作:创建新节点时,计算当前的最小元素(比较当前值 val 和前一个节点的 min 值 ),将新节点插入链表头部(head.next 指向新节点 )。
  • pop 操作:直接将 head.next 指向下下个节点,移除栈顶(链表头节点 )。
  • top 操作:返回 head.next.val ,即链表头节点的值。
  • getMin 操作:返回 head.next.min ,即链表头节点记录的当前栈最小元素。

三、代码实现与详细注释

class MinStack {// 自定义链表节点类,存储值、当前最小值、下一个节点static class Node {Node next = null;int val;int min;Node(int val, int min, Node next) {this.val = val;this.min = min;this.next = next;}}Node head; // 链表头节点,作为哨兵节点// 初始化栈,创建哨兵节点public MinStack() {// 哨兵节点val设为666(无实际意义),min设为Integer.MAX_VALUEhead = new Node(666, Integer.MAX_VALUE, null); }// 压栈操作public void push(int val) {// 计算新节点的min:前一个节点(head.next)的min(若存在)与当前val的较小值int currentMin = (head.next != null) ? head.next.min : head.min; currentMin = Math.min(currentMin, val);// 新节点插入链表头部(head.next指向新节点)Node newNode = new Node(val, currentMin, head.next); head.next = newNode;}// 弹栈操作:移除链表头节点(栈顶)public void pop() {if (head.next != null) { // 确保栈非空(实际使用中需处理空栈情况,题目测试用例保证合法操作)head.next = head.next.next; }}// 获取栈顶元素值public int top() {return head.next.val; // 链表头节点的val即为栈顶值}// 获取当前栈的最小元素public int getMin() {return head.next.min; // 链表头节点的min即为当前栈最小元素}
}

(一)代码流程拆解

  1. 初始化:创建 head 哨兵节点,其 min 设为 Integer.MAX_VALUE ,后续节点入栈时会动态计算真实的最小元素。
  2. push 操作
    • 计算当前新节点的 min 值:若链表已有节点(head.next != null ),则取 val 和前一个节点 min 的较小值;若链表为空(初始状态 ),则 val 就是当前最小。
    • 将新节点插入链表头部(head.next 指向新节点 ),保证栈顶始终是链表头节点。
  3. pop 操作:直接跳过链表头节点(head.next = head.next.next ),实现栈顶元素的移除。
  4. top 操作:返回链表头节点的 val 属性,即栈顶元素值。
  5. getMin 操作:返回链表头节点的 min 属性,即当前栈的最小元素,无需遍历,时间复杂度 O(1) 。

(二)关键逻辑解析

  • 哨兵节点的作用:简化链表操作,避免处理 head.next == null 的边界情况(如初始化时直接操作 head.next )。
  • 节点 min 属性的维护:每个节点在入栈时,主动记录当前栈的最小元素,使得 getMin 操作只需访问栈顶节点的 min 属性,保证了时间复杂度 O(1) 。
  • 链表结构的优势:栈的 pushpop 操作对应链表的头部插入和删除,时间复杂度均为 O(1) ,同时天然维护了栈的“后进先出”特性。

四、复杂度分析

(一)时间复杂度

  • push:O(1) 。创建新节点并插入链表头部,操作时间固定。
  • pop:O(1) 。只需修改链表指针,操作时间固定。
  • top:O(1) 。直接访问链表头节点的 val 属性。
  • getMin:O(1) 。直接访问链表头节点的 min 属性。

所有操作的时间复杂度均为 O(1) ,满足题目要求。

(二)空间复杂度

  • 每个元素入栈时,需存储一个 Node 对象,包含 valminnext 。空间复杂度为 O(n) ,n 为栈中元素的最大数量。
http://www.dtcms.com/a/340067.html

相关文章:

  • Android逆向工程:Smali语法解析完整指南
  • [ Maven 开发工具 ] 环境搭建及配置
  • DRM驱动架构浅析-上(DRM基础概要与U-Boot阶段驱动解析)
  • 基于 OpenMV 的矩形识别与 STM32 串口通信(电子设计大赛实用教程)
  • k8s运维实践:高可用Redis Cluster(三主三从)与Proxy部署方案
  • 使用 Docker 安装长安链管理平台 + 部署区块链与示例合约
  • daily notes[3]
  • Eigen中Dense 模块简要介绍和实战应用示例(最小二乘拟合直线、协方差矩阵计算和稀疏求解等)
  • 三极管驱动led灯搭配的电阻选取方法
  • 跟随广州AI导游深度探寻广州历史底蕴​
  • 如何做一次AIMD
  • 农田扫描提速37%!基于检测置信度的无人机“智能抽查”路径规划,Coovally一键加速模型落地
  • [OWASP]智能体应用安全保障指南
  • 英伟达显卡驱动怎么更新 详细步骤教程
  • MySQL练习题50题(附带详细教程)
  • Day13_【DataFrame数据组合concat连接】【案例】
  • C5.5:VDB及后面的电路讨论
  • 决策树(2)
  • Yum使用时报错
  • Spring Boot 全局异常处理
  • 快速了解Anaconda系统
  • 08.5【C++ 初阶】实现一个相对完整的日期类--附带源码
  • implement libtime on Windows
  • MyCAT基础概念
  • Python函数总结
  • week2-[一维数组]最大元素
  • 单细胞格式转换 rds 转成 h5ad
  • transformer模型初理解
  • Transformer、BERT、BEiT等模型相关八股及代码【自用】
  • HJ4 字符串分隔