构造一个可以在固定时间内返回最小元素值的栈

我一开始没想太多,觉得把标准库里现有的数据结构拼一下,完全就可以了,这是我的代码:

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 来存储。

原文地址:https://www.cnblogs.com/wuOverflow/p/4719820.html