Medium
题目描述
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack()初始化堆栈对象。void push(int val)将元素val推入堆栈。void pop()删除堆栈顶部的元素。int top()获取堆栈顶部的元素。int getMin()获取堆栈中的最小元素。
你必须实现 O(1) 时间复杂度的每个函数。
示例 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和getMin最多被调用3 * 10^4次
解题思路
这道题的关键在于如何在 O(1) 时间内获取栈中的最小元素。有两种经典的解法:
方法一:辅助栈 使用一个主栈存储所有元素,另外用一个辅助栈专门存储最小值。当 push 元素时,主栈正常添加元素;辅助栈只在新元素小于等于当前最小值时才添加。当 pop 元素时,如果弹出的元素等于当前最小值,辅助栈也要弹出一个元素。
方法二:单栈存储差值 使用一个栈存储当前元素与当前最小值的差值,同时维护一个变量记录当前最小值。这种方法更节省空间,但实现稍复杂。
推荐方法一,因为思路更清晰,实现更简单,且空间复杂度在实际应用中是可接受的。核心思想是用空间换时间,通过维护额外的最小值栈来确保 getMin 操作的 O(1) 时间复杂度。
代码实现
class MinStack {
private:
stack<int> stk;
stack<int> minStk;
public:
MinStack() {
}
void push(int val) {
stk.push(val);
if (minStk.empty() || val <= minStk.top()) {
minStk.push(val);
}
}
void pop() {
if (stk.top() == minStk.top()) {
minStk.pop();
}
stk.pop();
}
int top() {
return stk.top();
}
int getMin() {
return minStk.top();
}
};
class MinStack:
def __init__(self):
self.stk = []
self.min_stk = []
def push(self, val: int) -> None:
self.stk.append(val)
if not self.min_stk or val <= self.min_stk[-1]:
self.min_stk.append(val)
def pop(self) -> None:
if self.stk[-1] == self.min_stk[-1]:
self.min_stk.pop()
self.stk.pop()
def top(self) -> int:
return self.stk[-1]
def getMin(self) -> int:
return self.min_stk[-1]
public class MinStack {
private Stack<int> stk;
private Stack<int> minStk;
public MinStack() {
stk = new Stack<int>();
minStk = new Stack<int>();
}
public void Push(int val) {
stk.Push(val);
if (minStk.Count == 0 || val <= minStk.Peek()) {
minStk.Push(val);
}
}
public void Pop() {
if (stk.Peek() == minStk.Peek()) {
minStk.Pop();
}
stk.Pop();
}
public int Top() {
return stk.Peek();
}
public int GetMin() {
return minStk.Peek();
}
}
var MinStack = function() {
this.stack = [];
this.minStack = [];
};
MinStack.prototype.push = function(val) {
this.stack.push(val);
if (this.minStack.length === 0 || val <= this.minStack[this.minStack.length - 1]) {
this.minStack.push(val);
}
};
MinStack.prototype.pop = function() {
const popped = this.stack.pop();
if (popped === this.minStack[this.minStack.length - 1]) {
this.minStack.pop();
}
};
MinStack.prototype.top = function() {
return this.stack[this.stack.length - 1];
};
MinStack.prototype.getMin = function() {
return this.minStack[this.minStack.length - 1];
};
复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| push | O(1) | O(1) |
| pop | O(1) | O(1) |
| top | O(1) | O(1) |
| getMin | O(1) | O(1) |
| 整体空间复杂度 | - | O(n) |
其中 n 为栈中元素的个数。辅助栈在最坏情况下(元素递减序列)会存储所有元素,因此整体空间复杂度为 O(n)。
相关题目
. Sliding Window Maximum (Hard)
. Max Stack (Hard)