我一开始没想太多,觉得把标准库里现有的数据结构拼一下,完全就可以了,这是我的代码:
class MinStack {
private:
multiset<int> sortedElems;
list<int> stack;
public:
void push(int x) {
sortedElems.insert(x);
stack.push_back(x);
}
void pop() {
if (stack.empty()){
return;
}
sortedElems.erase(sortedElems.find(stack.back()));
stack.pop_back();
}
int top() {
return stack.back();
}
int getMin() {
return *sortedElems.cbegin();
}
};
这个思路有点偷懒,就是你既然要求返回最小元素所用的时间是固定的,那么原先理论上需要用来查找的开销我就挪到别的地方去,没错,我把它们分摊到了 pop() he push() 上。
但毕竟我的这个算法很愚蠢,所以就算是返回最小值的时间变短了,但总时间还是很长,效率低下, 共用了 54ms。
当我的方法不算是最快的那一种的时候,我就会看一下讨论区里其他朋友的方法,结果果然发现了更高效的方法,原代码是 Java 版本,我改写了自己的一份 C++ 版本:
class MinStack {
private:
long long min = 0;
stack<long long> _stack;
public:
void push(int x) {
auto&& n = static_cast<long long>(x);
if (_stack.empty()) {
_stack.push(0L);
min = n;
return;
}
_stack.push(n - min);
if (n < min){
min = n;
}
}
void pop() {
if (_stack.empty()){
return;
}
auto popedNum = _stack.top();
if (popedNum < 0L){
min -= popedNum;
}
_stack.pop();
}
int top() {
auto topNum = _stack.top();
if (topNum > 0) {
return static_cast<int>(min + topNum);
}
return static_cast<int>(min);
}
int getMin() {
return static_cast<int>(min);
}
};
这个算法很有意思,是一种空间换时间的策略,我之前的想法中,最小值和栈中存储的值是割裂开的,存储是存储,然后再单独求出最小值。
而这种方法就不同了,它是把最小值与每个值在 push() 时通过运算建立联系,并在 pop() 时通过逆运算求得原先的值,因此所用时间只有 28ms。
对了,还有一个细节要注意,就是用于存储的值,选用的类型是 long long。因为其中用到了加法,int 之间的相加可能会溢出,所以采用 long long 来存储。