最小栈、最大栈、双向支持的最小最大栈
✅ 什么是最小栈(Min Stack)?
最小栈是一种支持常数时间内(O(1)) 获取栈中最小值的栈结构。
🔧 标准栈的限制
通常,使用普通栈只能O(n) 时间遍历才能找出最小值:
| 1 | stack = [3, 4, 2, 5] | 
但最小栈支持:
- push(x):压入元素
- pop():移出栈顶
- top():查看栈顶元素
- getMin():O(1) 获取栈中最小值
🧠 核心思想
借助一个辅助栈来同步维护当前栈的最小值。例如:
| 操作 | 原始栈(main_stack) | 最小栈(min_stack) | 
|---|---|---|
| push(5) | 5 | 5 | 
| push(3) | 5, 3 | 5, 3 | 
| push(4) | 5, 3, 4 | 5, 3, 3 | 
| pop() | 5, 3 | 5, 3 | 
| getMin() | return 3 | top of min_stack | 
✅ Python 最小栈实现示例
| 1 | class MinStack: | 
🧰 操作说明
- push(val):将- val压入主栈;同时,将新最小值压入- min_stack
- pop():主栈和最小栈同时弹出
- getMin():直接返回- min_stack栈顶
🧮 时间复杂度
| 操作 | 时间复杂度 | 
|---|---|
| push() | O(1) | 
| pop() | O(1) | 
| top() | O(1) | 
| getMin() | O(1) | 
🚀 更加节省空间的变体(不重复最小元素)
上面的方法中 min_stack 与主栈等长,因为每次都同步 push,但你也可以只在 min 发生变化时记录保存:
| 1 | class MinStack: | 
🔸这种写法更节省空间,适用于要求内存优势的场合。
📌 典型应用场景
- 实现含最小值查询功能的数据结构
- 辅助解决滑动窗口、括号匹配、区间最小值等问题
- LeetCode 原题:155. 最小栈
✅ 总结
| 特性 | 说明 | 
|---|---|
| 支持操作 | push、pop、top、getMin | 
| 时间复杂度 | 所有操作均为 O(1) | 
| 核心数据结构 | 主栈 + 最小栈 | 
| 空间优化方法 | 只在 val <= 当前最小时记录 | 
| 当然可以!下面我们讨论一种扩展数据结构:同时支持 O(1) 查询最小值和最大值的栈,即: | 
✅ 双向支持的最小最大栈(MinMax Stack)
💡 需求描述
构建一个MinMax 栈,支持以下操作,且所有操作都为 O(1) 时间复杂度:
- push(val):将元素压入栈
- pop():移除栈顶
- top():返回栈顶元素
- getMin():返回当前栈中最小值
- getMax():返回当前栈中最大值
✅ 思路
除了维护主栈,我们再用两个辅助栈:
- min_stack:记录每一状态下的最小值
- max_stack:记录每一状态下的最大值
每次压栈时,同步更新 min_stack 和 max_stack。
🧠 图解(push 操作)
假设我们依次压入:[3, 2, 5, 1]
| Main Stack | Min Stack | Max Stack | 
|---|---|---|
| 3 | 3 | 3 | 
| 2 | 2 ← min(2,3) | 3 ← max(2,3) | 
| 5 | 2 | 5 | 
| 1 | 1 ← min(1,2) | 5 | 
✅ Python 实现
| 1 | class MinMaxStack: | 
✅ 示例用法
| 1 | s = MinMaxStack() | 
📊 时间 & 空间复杂度
| 方法 | 时间复杂度 | 空间复杂度(辅助栈) | 
|---|---|---|
| push | O(1) | O(n) | 
| pop | O(1) | O(1) | 
| top | O(1) | O(1) | 
| getMin | O(1) | O(1) | 
| getMax | O(1) | O(1) | 
✅ 空间优化(可选)
你可以进一步优化空间:只在新值小于等于当前 min / max 时才入栈
但这样做的话 pop() 时需要判断当前值是否是 min / max,略微增加复杂度。
例如:
| 1 | if not min_stack or val <= min_stack[-1]: | 
🔁 拓展
- 如果你还希望 getMin和getMax支持在 队列中 实现(单调队列),则涉及:- 单调栈 / 单调队列
- 滑动窗口(滑窗最大最小)
- 可参考:LeetCode 239 滑动窗口最大值
 
✅ 总结
| 结构 | 支持操作 | getMin / getMax | 时间复杂度 | 空间复杂度 | 
|---|---|---|---|---|
| 正常栈 | push, pop, top | ✗ | O(1) | O(n) | 
| 最小栈 | push, pop, top, getMin | ✓(min only) | O(1) | O(n) | 
| 最大栈 | push, pop, top, getMax | ✓(max only) | O(1) | O(n) | 
| MinMax栈 | push, pop, top, getMin, getMax | ✓(both) | O(1) | O(n) | 
这种结构在许多算法面试中是高频考点。灵活掌握它将对你解决各类 “最值 + 动态结构” 类问题非常有帮助。需要我给出相关题目练习吗?
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Min的博客!
 评论
