栈题解——最小栈【LeetCode】
155. 最小栈
题目描述
设计一个支持 push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
实现 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.
提示:
-231 <= val <= 231 - 1
pop
、top
和getMin
操作总是在 非空栈 上调用push
,pop
,top
, andgetMin
最多被调用3 * 104
次
我们来分析这段实现 支持常数时间获取最小值的栈(MinStack) 的代码,从三个角度出发:
一、算法逻辑讲解(思路分步)
整体目标:
设计一个栈结构,要求支持四种操作:
push(val)
: 入栈元素 val;pop()
: 弹出栈顶元素;top()
: 获取栈顶元素;getMin()
: 获取当前栈中的最小值。
初始化
self.st = [(0, inf)]
- 初始化时栈中放入一个哨兵
(0, inf)
。
-
0
是占位数,实际不用,避免栈为空的边界判断。inf
是正无穷,表示最小值的初始值永远不会被使用。- 用一个 二元组 表示栈元素:
(val, 当前最小值)
,这样可以实现 O(1) 取最小值。
push(val)
self.st.append((val, min(self.st[-1][1], val)))
- 每次压入新值
val
,同时记录当前栈中的最小值:
-
self.st[-1][1]
是栈顶记录的“之前”的最小值;min(...)
是“当前”与“之前”最小值取更小的那个;- 所以每个栈元素都带着“当前入栈时的最小值”。
pop()
self.st.pop()
- 弹出栈顶元素,直接
pop
即可; - 由于最小值是绑定在元素上的,所以不会丢失信息。
top()
return self.st[-1][0]
- 返回栈顶的元素值。
getMin()
return self.st[-1][1]
- 返回栈顶记录的当前最小值。
二、算法核心点(关键技巧)
✅ 核心技巧:栈中每个元素都附带一个当前最小值
这是本算法的关键优化 ——
- 在入栈的时候,提前计算好每个状态下的最小值并存储下来;
- 这样在
getMin()
的时候就能做到 O(1) 时间复杂度; - 所以不是每次动态去遍历栈找最小值,而是把“最小值随时间演变的轨迹”记录在每个节点中。
这种结构也被称为 “辅助栈思想” 的一种优化实现(实际上这里是“主栈 + 最小值绑定”)。
class MinStack:def __init__(self):# 这里的 0 写成任意数都可以,反正用不到self.st = [(0, inf)] # 栈底哨兵def push(self, val: int) -> None:self.st.append((val, min(self.st[-1][1], val)))def pop(self) -> None:self.st.pop()def top(self) -> int:return self.st[-1][0]def getMin(self) -> int:return self.st[-1][1]
三、复杂度分析
时间复杂度(所有操作):
push
: O(1)pop
: O(1)top
: O(1)getMin
: O(1)
因为每个操作都只涉及栈顶元素的访问或更新,无需遍历。
空间复杂度:
- O(n),其中 n 是入栈的元素个数。
- 每个元素都存储了一个
(val, 当前最小值)
的二元组,因此是线性空间。
总结
维度 | 说明 |
✅ 思路逻辑 | 每个入栈元素都记录当前最小值 |
✅ 核心技巧 | 元素与当前最小值打包记录,空间换时间 |
✅ 时间复杂度 | 所有操作均为 O(1) |
✅ 空间复杂度 | O(n),每个入栈值都额外记录一个最小值 |
如需我用图示说明这段栈在操作过程中的状态变化,也可以继续补充!