一、题目简介
题目描述
设计一个支持以下操作的栈:
-
push(x)------ 将元素 x 推入栈中 -
pop()------ 删除栈顶的元素 -
top()------ 获取栈顶元素 -
getMin()------ 检索栈中的最小元素
要求:
每个操作的时间复杂度必须是 O(1)。
二、思路分析
这道题的核心在于:
我们在每次 push 的时候,除了记录栈顶的值,还要顺便记录当前栈内的最小值。
换句话说,我们可以让每一层栈都携带两个信息:
pair<当前元素, 当前最小值>
这样一来,每次入栈或出栈时,我们都可以在 O(1) 时间内拿到最小值。
⚙️ 三、关键设计
1. 栈的结构设计
我们用一个栈 stack<pair<int, int>> 来存放数据:
-
first表示栈顶元素的值; -
second表示当前栈的最小值。
例如:
[(2, 2), (5, 2), (1, 1)]
此时:
-
栈顶
first=1; -
栈顶
second=1; -
当前最小值为 1。
2. 初始状态设计
我们在构造函数中手动压入一个初始值:
st.push(pair(0, INT_MAX));
为什么要这么做?
-
因为这样可以确保第一个入栈的元素一定比
INT_MAX小; -
避免在第一次
push时st.top()为空导致出错。
3.入栈逻辑
每当我们 push(val) 时:
-
当前最小值应为:
min(val, st.top().second)即「当前值」与「之前的最小值」中取较小的一个;
-
再用
pair{val, 当前最小值}压栈。
4️⃣ 出栈逻辑
直接 st.pop() 即可,当前最小值自动回退为下一个元素的 second。
5️⃣ top() 与 getMin()
因为 st.top() 返回的是一个 pair<int, int>:
-
st.top().first→ 栈顶元素; -
st.top().second→ 当前最小值。
四、完整代码
cpp
class MinStack {
// 思路: 维护栈顶的最小元素 pair<栈顶元素, 最小值>
stack<pair<int, int>> st;
public:
MinStack() {
// 初始时推入一个虚拟节点,避免空栈判断
st.push(pair(0, INT_MAX));
}
void push(int val) {
st.push(pair{val, min(val, st.top().second)});
}
void pop() {
st.pop();
}
int top() {
return st.top().first;
}
int getMin() {
return st.top().second;
}
};
五、运行逻辑示例
以 push(2), push(5), push(1) 为例:
| 操作 | 栈内容 (pair<值, 当前最小值>) |
|---|---|
| 初始 | [(0, INF)] |
| push(2) | [(0, INF), (2, 2)] |
| push(5) | [(0, INF), (2, 2), (5, 2)] |
| push(1) | [(0, INF), (2, 2), (5, 2), (1, 1)] |
此时:
-
top()→ 1 -
getMin()→ 1 -
pop()后最小值回退为 2
六、知识要点总结
| 知识点 | 说明 |
|---|---|
pair<int,int> |
同时存两个相关的变量 |
.first / .second |
分别取出 pair 中的两个值 |
st.top() |
返回栈顶元素(是 pair) |
INT_MAX |
初始化为无穷大,方便比较 |
min(a, b) |
返回较小值 |
七、总结
使用 pair 维护最小值 的思路非常高效:
-
不需要额外的数据结构;
-
所有操作都是 O(1);
-
逻辑简洁、实现优雅。
这类"带记忆功能"的栈思想非常常见,
比如 "含最大值的栈"、"含和的栈" 都能用相同的套路解决。