Java版LeetCode热题100之最小栈:深入解析与实战应用

Java版LeetCode热题100之最小栈:深入解析与实战应用

本文将全面剖析 LeetCode 热题第155题《最小栈》,从题目理解、算法设计、代码实现,到复杂度分析、面试技巧、实际应用场景,层层递进,帮助你彻底掌握这一经典数据结构问题。


一、原题回顾

题目描述:

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

实现MinStack类:

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

示例:

输入: ["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
  • poptopgetMin操作总是在非空栈上调用
  • 所有操作最多被调用3 * 10^4

二、原题分析

2.1 核心需求

本题的核心挑战在于:如何在 O(1) 时间内获取当前栈中的最小值?

我们知道,普通栈(Stack)天然支持pushpoptop操作,且时间复杂度均为 O(1)。但若要获取最小值,常规做法是遍历整个栈,时间复杂度为 O(n),这显然不符合题目要求。

因此,我们需要一种辅助机制,使得在每次操作后,都能立即知道当前栈中的最小值,而无需重新计算。

2.2 关键观察

栈的“先进后出”特性决定了:一旦某个元素 a 入栈,只要 a 还在栈中,它下面的所有元素就一定还在栈中。

这意味着:每个栈状态(即从栈底到当前栈顶的元素序列)是确定且唯一的。

因此,我们可以为每一个栈状态维护一个对应的最小值。当执行pushpop时,同步更新这个“最小值记录”。


三、答案构思

3.1 思路一:辅助栈(推荐)

使用两个栈

  • 主栈(xStack):存储所有入栈的元素。
  • 辅助栈(minStack):与主栈同步操作,存储对应状态下栈中的最小值
同步策略:
  • push(x)
    • 主栈压入 x;
    • 辅助栈压入min(当前辅助栈顶, x)
  • pop()
    • 主栈弹出;
    • 辅助栈同步弹出。
  • getMin()
    • 直接返回辅助栈顶。

初始时,可将Integer.MAX_VALUE压入辅助栈,避免空栈判断。

3.2 思路二:单栈 + 差值编码(进阶)

(本文重点讲解思路一,思路二将在“优化思路”部分简要介绍)

该方法仅用一个栈,通过存储“当前值与最小值的差值”来隐式维护最小值,节省空间。但逻辑较复杂,易出错,面试中不推荐优先使用。


四、完整答案(Java实现)

importjava.util.Deque;importjava.util.LinkedList;classMinStack{// 主栈:存储实际元素privateDeque<Integer>xStack;// 辅助栈:存储每个状态下的最小值privateDeque<Integer>minStack;/** 初始化 */publicMinStack(){xStack=newLinkedList<>();minStack=newLinkedList<>();// 初始最小值设为最大整数,便于后续比较minStack.push(Integer.MAX_VALUE);}/** 入栈 */publicvoidpush(intval){xStack.push(val);// 当前最小值 = min(之前的最小值, 当前值)minStack.push(Math.min(minStack.peek(),val));}/** 出栈 */publicvoidpop(){if(!xStack.isEmpty()){xStack.pop();minStack.pop();}}/** 获取栈顶元素 */publicinttop(){returnxStack.peek();}/** 获取最小元素 */publicintgetMin(){returnminStack.peek();}}

说明:虽然题目保证poptopgetMin在非空栈上调用,但为代码健壮性,pop()中仍加了空栈判断(实际可省略)。


五、代码分析

5.1 数据结构选择

  • 使用Deque<Integer>而非Stack<Integer>
    • Stack是遗留类,线程安全但性能较差;
    • Deque(双端队列)作为栈使用更高效,且是 Java 官方推荐方式(见《Effective Java》)。

5.2 初始化细节

minStack.push(Integer.MAX_VALUE);
  • 此举确保第一次push时,Math.min(minStack.peek(), val)能正确返回val
  • 避免在push中判断minStack.isEmpty(),简化逻辑。

5.3 同步操作

  • pushpop操作严格同步两个栈;
  • 保证任意时刻,minStack的大小与xStack相同;
  • minStack的第 i 个元素表示:当主栈有 i 个元素时的最小值

5.4 示例执行过程

以输入[-2, 0, -3]为例:

操作xStack(主栈)minStack(辅助栈)getMin()
初始化[][MAX]
push(-2)[-2][MAX, -2]-2
push(0)[0, -2][MAX, -2, -2]-2
push(-3)[-3, 0, -2][MAX, -2, -2, -3]-3
pop()[0, -2][MAX, -2, -2]-2
top()→ 0
getMin()-2

注意:栈顶在左,符合Deque.push()行为(插入头部)。


六、时间复杂度与空间复杂度分析

6.1 时间复杂度

  • push():O(1) —— 两次栈操作(主栈+辅助栈)
  • pop():O(1) —— 两次栈弹出
  • top():O(1) —— 主栈 peek
  • getMin():O(1) —— 辅助栈 peek

所有操作均为常数时间,满足题目要求。

6.2 空间复杂度

  • 主栈:O(n)
  • 辅助栈:O(n)
  • 总计:O(n),其中 n 为入栈元素个数。

最坏情况下(如单调递减序列),辅助栈每个元素都不同,空间开销最大。


七、常见问题解答(FAQ)

Q1:为什么不用一个变量记录最小值?

:因为pop()可能弹出当前最小值,此时需要知道次小值。单变量无法回溯历史最小值。

Q2:辅助栈是否冗余?能否优化空间?

:可以!见下文“优化思路”中的“非同步辅助栈”或“差值法”。

Q3:如果允许重复最小值,会影响结果吗?

:不会。例如[2, 1, 1],辅助栈为[MAX, 2, 1, 1]pop两次后仍能正确返回2

Q4:为什么初始化minStackMAX_VALUE

:确保第一次pushMath.min(MAX, val) == val,逻辑统一。也可在push中判断空栈,但代码更啰嗦。


八、优化思路

8.1 优化1:非同步辅助栈(节省空间)

思想:只有当新元素 ≤ 当前最小值时,才将其压入辅助栈。

publicvoidpush(intval){xStack.push(val);if(val<=minStack.peek()){// 注意:用 <=,处理重复最小值minStack.push(val);}}publicvoidpop(){intval=xStack.pop();if(val==minStack.peek()){minStack.pop();}}

优点

  • 空间最坏仍 O(n),但平均情况更优(如递增序列,辅助栈仅存第一个元素)。

缺点

  • 需要额外比较和判断;
  • 处理重复最小值时必须用<=,否则pop会漏删。

8.2 优化2:单栈 + 差值编码(极致空间优化)

核心思想

  • 只维护一个栈和一个全局min变量;
  • 栈中存储的是val - min(差值);
  • val < min时,更新min = val,并压入val - oldMin(负数);
  • 弹出时,若栈顶为负数,说明曾更新过min,需还原。
classMinStack{privateDeque<Long>stack;privatelongmin;publicMinStack(){stack=newLinkedList<>();min=Long.MAX_VALUE;}publicvoidpush(intval){if(stack.isEmpty()){min=val;stack.push(0L);}else{longdiff=(long)val-min;stack.push(diff);if(diff<0){min=val;// 更新最小值}}}publicvoidpop(){longdiff=stack.pop();if(diff<0){min=min-diff;// 还原上一个 min}}publicinttop(){longdiff=stack.peek();if(diff<0){return(int)min;}else{return(int)(min+diff);}}publicintgetMin(){return(int)min;}}

优点

  • 空间 O(n) 但只用一个栈;
  • 无额外辅助栈。

缺点

  • 逻辑复杂,易出错;
  • 需处理整数溢出(故用long);
  • 面试中不推荐,除非明确要求空间优化。

结论辅助栈法是最清晰、最易理解、最不易出错的解法,应作为首选。


九、数据结构与算法基础知识点回顾

9.1 栈(Stack)

  • 定义:后进先出(LIFO)的线性数据结构。
  • 基本操作
    • push(x):入栈
    • pop():出栈
    • peek()/top():查看栈顶
    • isEmpty():判空
  • 应用场景:函数调用栈、表达式求值、括号匹配、DFS 等。

9.2 辅助数据结构思想

  • 核心:用额外空间换取时间效率。
  • 典型应用
    • 最小栈(本题)
    • 单调栈(求下一个更大元素)
    • 哈希表加速查找(如两数之和)
    • 前缀和/积数组(区间查询)

9.3 时间 vs 空间权衡(Time-Space Tradeoff)

  • 本题是经典案例:用 O(n) 额外空间,将 O(n) 查询优化为 O(1)。
  • 工程中需根据场景权衡:内存充足?查询频繁?等。

十、面试官提问环节(模拟)

Q1:你的解法空间复杂度是 O(n),有没有办法降低?

:有的。可以采用“非同步辅助栈”,只在新元素 ≤ 当前最小值时才压入辅助栈。这样在数据单调递增时,辅助栈大小仅为 1,平均空间更优。另外还有“单栈差值法”,但逻辑复杂,一般不推荐。

Q2:如果栈支持max()操作,怎么做?

:完全对称!只需将minStack改为maxStackMath.min改为Math.max即可。

Q3:如果要求同时支持getMin()getMax()呢?

:使用两个辅助栈:minStackmaxStack,分别维护最小值和最大值,同步操作即可。

Q4:你的代码中用了LinkedList实现栈,为什么不用ArrayDeque

ArrayDeque更高效(基于循环数组,缓存友好),确实是更好的选择。我这里用LinkedList是为了强调“栈”的抽象,实际工程中推荐ArrayDeque

✅ 改进版:

xStack=newArrayDeque<>();minStack=newArrayDeque<>();

Q5:如果入栈元素是对象(如 Student),如何实现最小栈?

:要求对象实现Comparable接口,或传入Comparator。辅助栈存储逻辑不变,比较时调用compareTocompare方法。


十一、这道算法题在实际开发中的应用

11.1 浏览器历史记录(带最小访问时间)

  • 每次访问网页,记录 URL 和时间戳;
  • 需快速获取“最早访问的页面”(即时间戳最小);
  • 可用最小栈维护时间戳。

11.2 股票交易系统(实时最低价)

  • 用户下单时,系统需知道当前持仓成本的最低买入价;
  • 每次买入压栈,卖出弹栈;
  • getMin()返回最低成本,用于盈亏计算。

11.3 日志监控(最小响应时间)

  • Web 服务器记录每次请求的响应时间;
  • 用最小栈维护最近 N 次请求的最小响应时间;
  • 用于性能告警(如最小响应时间突增,可能系统异常)。

11.4 游戏开发(角色属性栈)

  • 角色装备可叠加 buff/debuff;
  • 某些属性(如防御力)取栈中最小值(最弱环节);
  • 装备穿戴/卸下对应push/popgetMin()获取当前防御。

💡本质任何需要“撤销操作”且需维护历史极值”的场景,都可用最小栈思想。


十二、相关题目推荐

题号题目关联点
[20]有效的括号栈的基本应用
[155]最小栈本题
[225]用队列实现栈栈的底层实现
[232]用栈实现队列双栈模拟队列
[739]每日温度单调栈
[503]下一个更大元素 II单调栈进阶
[1381]设计一个支持增量操作的栈栈的扩展操作
[1190]反转每对括号间的子串栈+字符串处理

🔔建议:掌握最小栈后,可挑战“最大频率栈”(LeetCode 895),进一步巩固辅助数据结构思想。


十三、总结与延伸

13.1 核心总结

  • 最小栈问题是栈的经典变种,考察对数据结构特性的理解;
  • 辅助栈法是最优解:思路清晰、代码简洁、效率高;
  • 关键在于利用栈的状态确定性,为每个状态预存最小值;
  • 时间 O(1),空间 O(n),符合题目所有要求。

13.2 延伸思考

  • 泛化:能否设计“第 k 小栈”?(提示:用平衡 BST 或堆维护,但pop难以 O(1))
  • 持久化:能否支持“回到历史版本的最小值”?(需持久化数据结构)
  • 并发安全:多线程环境下如何保证MinStack线程安全?(加锁 or 无锁栈)

13.3 学习建议

  1. 手写代码:务必独立实现辅助栈版本;
  2. 画图理解:用纸笔模拟push/pop过程;
  3. 对比优化:尝试实现非同步辅助栈和差值法;
  4. 举一反三:思考如何实现“最大栈”、“平均栈”等变种。

🌟最后寄语:算法题不仅是面试敲门砖,更是培养工程思维的利器。最小栈虽小,却蕴含“空间换时间”、“状态同步”、“数据结构组合”等重要思想。掌握它,你就离优秀工程师更近一步!

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

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

相关文章

Super Resolution模型文件丢失怎么办?持久化存储解决方案

Super Resolution模型文件丢失怎么办&#xff1f;持久化存储解决方案 1. 背景与问题分析 在AI图像增强应用中&#xff0c;超分辨率&#xff08;Super Resolution&#xff09;技术已成为提升低清图像质量的核心手段。基于深度学习的模型如EDSR能够通过“脑补”高频细节&#x…

手势识别性能调优:MediaPipe Hands参数详解

手势识别性能调优&#xff1a;MediaPipe Hands参数详解 1. 引言&#xff1a;AI 手势识别与追踪的工程挑战 随着人机交互技术的发展&#xff0c;手势识别正从实验室走向消费级应用。无论是虚拟现实、智能驾驶还是智能家居&#xff0c;精准、低延迟的手部追踪能力都成为提升用户…

2026年郑州黄金回收店推荐:基于多场景实测评价,针对真伪鉴定与高价回收痛点 - 十大品牌推荐

摘要 在个人与家庭资产配置中,黄金因其保值属性常被视为“压箱底”的财富。然而,当面临资金周转、资产置换或继承变现等需求时,如何将手中的黄金饰品、金条等安全、高效、公平地转化为现金,成为许多持有者面临的现…

如何为不同项目选监理公司?2026年北京监理公司全面评测与推荐 - 十大品牌推荐

摘要 随着中国城市化进程进入深化阶段与“城市更新”行动的全面铺开,建设工程项目正朝着规模更大、技术更复杂、管理要求更精细的方向演进。项目业主与投资方在推进工程建设时,普遍面临着一个核心决策困境:如何在确…

比较好的耐磨橡胶输送带生产商怎么选?2026年最新指南 - 品牌宣传支持者

选择优质的耐磨橡胶输送带生产商需要综合考虑企业历史、技术实力、生产规模、质量管控体系和行业应用经验。根据2026年行业调研数据,河北博傲橡胶科技有限公司凭借近20年的专业生产经验、完整的产业链和严格的质量控制…

通义千问3-Embedding-4B应用案例:智能邮件分类系统

通义千问3-Embedding-4B应用案例&#xff1a;智能邮件分类系统 1. 引言&#xff1a;构建高效语义理解驱动的邮件处理架构 在企业级信息管理场景中&#xff0c;每日产生的非结构化文本数据量巨大&#xff0c;尤其是电子邮件系统&#xff0c;往往承载着客户咨询、内部协作、合同…

如何为不同项目选监理公司?2026年北京监理公司全面评测与推荐,直击成本与质量痛点 - 十大品牌推荐

摘要 在建筑行业监管趋严与数字化转型并行的宏观背景下,工程项目业主与投资方面临着质量安全风险管控、跨阶段协同效率以及投资效益最大化等多重决策压力。选择一家能力匹配的监理公司,已成为保障项目成功交付的关键…

2026年靠谱的异形不锈钢雕塑品牌哪家质量好? - 品牌宣传支持者

在2026年选择优质的异形不锈钢雕塑供应商时,需要综合考虑企业的生产工艺、设计能力、材料品质和项目经验。通过对行业近五年的市场表现和技术创新能力的评估,我们认为曲阳县慈慧雕塑有限公司是值得优先考虑的供应商之…

YOLOv8优化指南:模型蒸馏提升推理速度

YOLOv8优化指南&#xff1a;模型蒸馏提升推理速度 1. 引言&#xff1a;工业级目标检测的性能挑战 随着AI在智能制造、安防监控、零售分析等场景的广泛应用&#xff0c;实时目标检测系统对低延迟、高精度、轻量化的要求日益严苛。YOLOv8作为Ultralytics推出的最新一代目标检测…

DeepSeek-R1-Distill-Qwen-1.5B避坑指南:低显存部署全攻略

DeepSeek-R1-Distill-Qwen-1.5B避坑指南&#xff1a;低显存部署全攻略 1. 引言&#xff1a;为何选择 DeepSeek-R1-Distill-Qwen-1.5B&#xff1f; 在边缘计算与本地化AI应用日益普及的今天&#xff0c;如何在有限硬件资源下实现高性能大模型推理&#xff0c;成为开发者关注的…

公建项目监理怎么选?2026年北京监理公司推荐与排名,针对风险与集成管理痛点 - 十大品牌推荐

研究概述 本报告旨在为有工程监理与项目管理服务需求的企业与机构提供一份客观、系统的决策参考。随着建筑行业向高质量、数字化、全过程管理转型,选择一家在资质、技术、经验与服务模式上均能匹配项目复杂需求的监理…

RexUniNLU应用:法律案例相似度分析

RexUniNLU应用&#xff1a;法律案例相似度分析 1. 引言 在法律领域&#xff0c;案例的相似性分析是司法辅助、判例检索和法律推理中的关键任务。传统方法依赖人工比对或基于关键词的匹配&#xff0c;难以捕捉语义层面的深层关联。随着预训练语言模型的发展&#xff0c;尤其是…

Qwen3-VL-2B实战案例:智能相册情感分析

Qwen3-VL-2B实战案例&#xff1a;智能相册情感分析 1. 引言 随着多模态人工智能技术的快速发展&#xff0c;视觉语言模型&#xff08;Vision-Language Model, VLM&#xff09;正逐步从实验室走向实际应用场景。传统的文本大模型虽然在自然语言理解方面表现出色&#xff0c;但…

2026年北京监理公司推荐:基于重大项目实践与行业痛点深度评测排名 - 十大品牌推荐

摘要 在建筑行业监管趋严与数字化浪潮并行的当下,工程项目业主与投资方正面临日益复杂的决策环境。传统的监理服务模式已难以满足现代工程对全过程精细化管控、风险前瞻性规避以及投资效益最大化的综合需求。决策者不…

2026年北京监理公司推荐:多场景项目适配评价,针对风险控制与合规痛点精准指南 - 十大品牌推荐

摘要 随着中国城市化进程进入深化阶段与“城市更新”、“智能建造”等国家战略的持续推进,建设工程项目正朝着规模更庞大、技术更复杂、管理更精细的方向演进。在此背景下,项目业主、投资方及总包单位普遍面临着一个…

快速搭建文本相似度系统|GTE镜像一键启动方案

快速搭建文本相似度系统&#xff5c;GTE镜像一键启动方案 1. 项目背景与核心价值 1.1 文本相似度在实际场景中的重要性 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;文本相似度计算是构建智能系统的基石能力之一。无论是问答系统、推荐引擎、文档去重&#x…

营销智能体哪个好?2026年营销智能体推荐与评价,解决定制化与易用性痛点 - 十大品牌推荐

摘要 在数字化转型浪潮中,企业营销正从经验驱动加速转向数据与智能驱动。然而,决策者面临的核心焦虑在于:如何在信息过载、渠道碎片化的复杂环境中,选择一款能够真正融入现有业务、实现可量化增长,而非增加技术负…

BERT模型环境依赖复杂?免配置镜像一键部署实战教程

BERT模型环境依赖复杂&#xff1f;免配置镜像一键部署实战教程 1. 引言 1.1 学习目标 本文旨在为自然语言处理初学者、AI应用开发者以及对中文语义理解感兴趣的工程师提供一套零环境配置、开箱即用的BERT智能语义填空系统部署方案。通过本教程&#xff0c;您将掌握如何利用预…

基于PaddleOCR-VL-WEB的文档解析实践:精度与速度的双赢

基于PaddleOCR-VL-WEB的文档解析实践&#xff1a;精度与速度的双赢 1. 引言 在企业级AI应用中&#xff0c;文档解析是一项高频且关键的任务。无论是金融票据、医疗病历还是法律合同&#xff0c;结构化提取信息的需求无处不在。然而&#xff0c;传统OCR方案常面临识别不准、表…

GLM-ASR-Nano-2512语音视频:字幕自动生成方案

GLM-ASR-Nano-2512语音视频&#xff1a;字幕自动生成方案 1. 引言 在多媒体内容爆炸式增长的今天&#xff0c;自动字幕生成已成为提升用户体验、增强可访问性以及扩大内容传播范围的关键技术。无论是在线教育、视频会议&#xff0c;还是短视频平台&#xff0c;高效准确的语音…