- 基础问题
最小栈
- 2025-8-28 22:39:29 @
题意概括
要求设计并实现一个特殊的栈结构,除了要支持常规栈的 push
(入栈)、pop
(出栈) 和 top
(查看栈顶) 操作外,还必须额外实现一个 getMin
方法。这个 getMin
方法需要能够在常数时间复杂度 O(1) 内,返回该栈中当前所有元素的最小值。
操作说明:
push x
: 将整数x
压入栈。pop
: 弹出栈顶元素。top
: 返回栈顶元素的值。getMin
: 返回栈中当前的最小值。
数据范围:
- 操作总数 满足 。
- 压入的整数 范围为 。
基础知识
解决本题的关键在于如何设计数据结构,使得 getMin
操作能够达到 的时间复杂度,同时不影响其他基本操作的效率。常规的栈在查找最小值时需要遍历所有元素,复杂度为 ,不符合题意。
辅助栈法 (Auxiliary Stack):
这是实现“最小栈”最经典和直观的方法。我们使用两个栈协同工作:
- 数据栈 (Data Stack): 一个普通的栈,用来存储所有被压入的元素。我们称之为
stk
。 - 辅助栈 (Minimum Stack): 另一个栈,我们称之为
mstk
。这个栈的特殊之处在于,它的栈顶元素永远是当前数据栈stk
中所有元素的最小值。它是一个单调不增的栈。
操作逻辑实现:
-
push x
操作:- 将元素
x
正常压入数据栈stk
。 - 检查辅助栈
mstk
:- 如果
mstk
为空,或者新元素x
小于或等于mstk
的栈顶元素,那么就将x
也压入mstk
。 - (使用“小于等于”是为了正确处理多个相同最小值的情况。当一个最小值被弹出后,如果栈中还有与之相等的元素,
mstk
依然能正确指向它。)
- 如果
- 将元素
-
pop
操作:- 首先,查看即将从
stk
弹出的元素stk.top()
。 - 如果这个元素恰好与
mstk
的栈顶元素相等,说明当前栈中的最小值即将被移除。因此,mstk
也需要弹出其栈顶元素,以确保mstk
的新栈顶是stk
剩余元素中的最小值。 - 最后,将
stk
的栈顶元素弹出。
- 首先,查看即将从
-
top
操作: 直接返回stk
的栈顶元素stk.top()
。 -
getMin
操作: 由于mstk
的栈顶始终保存着当前最小值,所以直接返回mstk.top()
即可。这是一个 操作。
复杂度分析:
- 所有操作 (
push
,pop
,top
,getMin
) 的时间复杂度均为 。 - 空间复杂度为 。在最坏情况下(例如,压入的元素序列是严格递减的),辅助栈
mstk
需要存储所有N
个元素。
C++ 解决方案
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void slv() {
int n;
// 使用 long long 防止整数溢出
stack<ll> stk, mstk;
cin >> n;
for (int i = 0; i < n; ++i) {
string op;
cin >> op;
if (op == "push") {
ll x;
cin >> x;
stk.push(x);
// 关键:当辅助栈为空或x小于等于其栈顶时,x入辅助栈
if (mstk.empty() || x <= mstk.top()) {
mstk.push(x);
}
} else if (op == "pop") {
// 如果弹出的元素是当前最小值,辅助栈也要弹出
if (stk.top() == mstk.top()) {
mstk.pop();
}
stk.pop();
} else if (op == "top") {
cout << stk.top() << endl;
} else if (op == "getMin") {
cout << mstk.top() << endl;
}
}
}
int main() {
// 关闭同步流,加速IO
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// 如果是严格的多组,可以用 while(cin >> n) { ... }
slv();
return 0;
}
/*
样例输入 1:
8
push -2
push 0
push -3
getMin
pop
top
getMin
样例输出 1:
-3
0
-2
样例输入 2:
5
push 5
push 3
getMin
push 1
getMin
样例输出 2:
3
1
*/
0 条评论
目前还没有评论...