PTA 155.最小栈

155. 最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

示例:

输入:

["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:

[null,null,null,null,-3,null,0,-2]

解释:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

提示:

pop、top 和 getMin 操作总是在 非空栈 上调用。


疑问

​当时我看到这一道题目的时候,首先想到的是用一个min值保存当前最小的值,但是转念一想,如果min就是栈顶元素,那么一旦pop()之后,min还是最小值吗?题目要求的要在 O ( 1 ) O(1) O(1)的时间内获取栈内元素最小值,那么只用一个min肯定就不行了,因为min只能保存一次最小值,一旦pop之后,min就未必是栈内剩余元素的最小值了。这里就为后面要学的内容 单调栈 埋下了伏笔。

辅助栈

​ 辅助栈,顾名思义,就是辅助的栈,这个栈的功能就是保存当前栈内最小元素的值。
在这里插入图片描述

​ 辅助栈的思路呢,就是说创建一个新的栈,姑且叫他最小栈吧,每当数据栈插入一个新元素的时候,就与最小栈的栈顶元素进行比较,如果新插入的数据小于等于最小栈的栈顶元素,那么就把这个数据插入到最小栈中。

为什么要这么做呢

首先我们来看题目,要求输出最小值,那么我创建一个min_Stack用来保存当前数据栈中的最小值,首先第一个元素插入进来,那么它一定是当前的最小值(毕竟就一个元素嘛),所以插入到min_Stack中。然后插入第二个元素,如果这个新元素大于min_Stack中的栈顶元素,那么他肯定不是当前最小的元素,不插入了,没啥好说的。如果小于等于min_Stack的栈顶元素的话,那么说明新来的就是当前栈中的最小元素,所以插入到最小栈中,这样就可以保证min_Stack中的元素一定是从栈底到栈顶降序(不太准确,应该是非升序)(因为新插入到最小栈的元素一定比栈顶元素小(或者等于))。然后当数据栈出栈的时候,判断数据栈栈顶元素和最小栈栈顶元素是否相等,如果相等,那么就同时pop,否则只有数据栈pop

为什么判断的时候是 小于等于 呢?

​比如现在有一个序列5,4,3,3,3,3,5,4,现在我把5,4,3插入到最小栈中了,下一个新数据 x 还是3,假设我不插入的话,那么最终的最小栈数据为5,4,3,然而这个程序的逻辑就是如果最小栈元素和数据栈栈顶元素相等时,两个栈都pop,假如我现在把数据栈中的 3 给pop了,因为最小栈的栈顶也是 3 ,所以也跟着pop,但是数据栈的栈顶元素还是 3 ,而最小栈中的数据是5,4,也就是说如果数据栈中插入的元素是相同的时候,也需要插入到最小栈中。

​ 下面是程序的代码:

class MinStack {
    
    
public:
    /** initialize your data structure here. */
    stack<int>data_Stack;
    stack<int>min_Stack;
    MinStack() {
    
    
    }
    void push(int x) {
    
    
        //如果最小栈为空或者最小栈栈顶元素 大于等于 x,那么就push
        if(min_Stack.empty() || min_Stack.top() >= x)min_Stack.push(x);
        data_Stack.push(x);
    }
    
    void pop() {
    
    
        if(min_Stack.top() == data_Stack.top())min_Stack.pop();
        data_Stack.pop();
    }
    
    int top() {
    
    
        return data_Stack.top();
    }
    
    int getMin() {
    
    
        return min_Stack.top();
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

如何理解最小栈呢?

其实我感觉这个最小栈有点类似于“养备胎”,我想要找到最爱我的女生。有一个“女人栈”和一个“女友栈”,“女人栈”是苍天让我遇到的所有女生,我的所有女友都要在这里找,“女友栈”的栈顶元素是我的现女友,现女友以下皆为“备胎”。现在来了一个女生,她是第一个,只能是她,所以我就把这个女生先push进“现女友栈”,直到苍天又给我的“女人栈”中push了另外一个更优秀的女生,她更爱我,所以我就把她push到“现女友栈”,作为栈顶女友,栈顶女友下面的都是备胎女友,直到。。。。直到我遇到了新push进来的女生,假如她没有我的现女友更爱我,那我的现女友栈的栈顶不变(没有我的现女友爱我,我为什么要让她当新女友),所以如果后push进来的女生如果没有现女友更爱我,她们爱咋咋地,我的现女友不会变,但是直到我的“女人栈”里的栈顶元素就是我的现女友了,她不爱我了,她要走,那我只能忍痛割爱,把我的“现女友栈”的栈顶元素给pop了,正式启用“备胎1号”,直到,,,直到一个备胎都没有了,并且我的“女人栈”里也一个也没有了。唉,早知道就不养备胎了,进来一个我就直接return了。



新节点法

​ 创建一个节点,保存当前的数据值和最小值

​ 这个其实很好理解,所以我不想多说了,直接看代码吧。

class MinStack {
    
    
public:
    /** initialize your data structure here. */
    struct Node
    {
    
    
        int val;
        int min;
        Node(int v,int m):val(v),min(m){
    
    }; //相当于构造函数吧
    };
    stack<Node>sta;
    MinStack() {
    
    
    }
    void push(int x) {
    
    
        //把新元素与栈顶元素的min进行比较
        if(sta.empty())sta.push(Node(x,x));
        else sta.push(Node(x,min(x,sta.top().min)));
    }
    
    void pop() {
    
    
        sta.pop();
    }
    
    int top() {
    
    
        return sta.top().val;
    }
    
    int getMin() {
    
    
        return sta.top().min;
    }
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(x);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

​ 这个方法真的太好了,比上面的简洁,我感觉效率还挺高。

​ 就先写上面这两种方法吧,感觉最小栈的方法挺不错的,大家还有相似的题目吗?

猜你喜欢

转载自blog.csdn.net/qq_27168967/article/details/108808409
今日推荐