获得栈中最小元素(时间复杂度为1)优化

版权声明:本文为博主原创文章,欢迎分享!吾生有涯而知也无涯,一起加油 https://blog.csdn.net/qq_41822235/article/details/82468584

变量命名说明: mins  (min stack缩写)  data   (数据栈)

剑指offer经典解法  很朴素、直接:辅助栈mins存储每次push时的最小值;pop时辅助栈mins和数据栈data两栈同步pop。

时间复杂度O(1),空间复杂度(n)

人生就是一个不断追求极致的过程,生活就是艺术——代码更是艺术。存在一个不太合理的地方——mins栈会保留大量冗余的最小值。如2、1、2、3、4、5、6顺次入栈:

图1  剑指offer解法的不合理之处

讨论:从图1 我们可以看到,mins保留了大量冗余的最小值。这也许是可以避免的(之所以这么说,万一没有办法解决这个问题,也就不可避免了,嘿嘿)。

mins不允许出现冗余,所有值都顺次只允许出现一次不就行了?但这带来了新问题。细想:该思路的要求是?push时进行判断,如果要入栈的元素比当前最小值大,mins保持不变;当push一个和当前最小值相等的元素,仍需要入栈;否则,mins栈中的栈顶元素pop出去之后,data栈中还可能存在最小值元素吗?这种情况是可以发生的,但此时mins却已经不含最小值元素,min()函数直接返回mins的栈顶元素,返回就不正确了!!!所以在这种思路的引导下,冗余是不可缺少的、是必要的。

本篇博客立足于如何优化剑指offer的解法

mins出现大量冗余的根源是什么呢?pop时辅助栈mins和数据栈data两栈会同步pop——有没有一种方法,使之pop时,mins到底是否执行pop额外判断一下;毫无疑问,数据栈data肯定还是要执行pop。 

革新:mins中存放最小值在data中的索引(先来后到)。如果push一个和最小值相同的元素,mins不需要改变;pop时,如果data将要除去的元素的索引不是mins栈顶元素,mins不执行出栈操作。

获得栈中最小元素的min()函数的实现思路:拿到mins栈顶元素作为索引,再去data中找到相应的元素作为最小值(按图索骥大概就是这个意思吧)——由此我们知道,data应该采用vector<int>,因为需要满足随机存取的特点。

图2  剑指offer解法的革新

C++代码实现如下 

class Solution {
public:
    void push(int value) {
        data.push_back(value);
        if(mins.empty())    
            mins.push(0);    //初始化mins栈
        else{
            if(value < min())
                mins.push(data.size() - 1);    //压入更新后最小值的索引
        }
    }
    void pop() {
        if(!data.empty()){
            if(data.size() - 1 == mins.top())    //pop出的元素索引如果是mins栈顶元素,执行出栈
                mins.pop();
            data.pop_back();    //删除最后一个元素  后进先出
        }
    }
    int top() {
        return data[data.size() - 1];
    }
    int min() {
        return data[mins.top()];
    }
private:
    vector<int>data;
    stack<int>mins;
};
图3  优化后的剑指offer的解法

猜你喜欢

转载自blog.csdn.net/qq_41822235/article/details/82468584
今日推荐