描述

这是一篇面对初级coder的题解。
知识点:栈
难度:二星


题解

题目
定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数,并且调用 min函数、push函数 及 pop函数 的时间复杂度都是 O(1)
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素

这道题考察栈的知识:
本题难点是如何维护最小元素,如果用一个单一值来记录最小值,
最小值出栈后就会用O(n)复杂度重新查找,最坏情况时间复杂度O(n),不符合题目要求

双栈法

可以采用一个最小元素的栈来维护这样一个数据结构



#include <stack>
class Solution {
    stack<int> data,mindata;//双栈法,维护一个数据栈和一个最小值栈
public:
    void push(int value) {
        data.push(value);//数据栈入栈
        if(mindata.size()==0||value<=mindata.top())//如果入栈值小于等于最小值,或当前栈为空
            mindata.push(value);//,最小值栈入栈
    }
    void pop() {
        if(mindata.top()==data.top())//如果出栈是当前的最小值
            mindata.pop();//最小值栈出栈
        data.pop();//数据栈出栈
    }
    int top() {
        return data.top();//返回数据栈栈顶元素
    }
    int min() {
        return mindata.top();//返回最小值栈栈栈顶元素
    }
};                    
	
  • 时间复杂度: O(1)
  • 空间复杂度: O(n),最坏情况要保存全部值。
  • 运行时间7ms  占用内存620KB

残差法

能否在时间复杂度不变的前提下,进一步缩小空间复杂度?
可以在栈中只记录与最小值的差,
那么就存在一个问题,随着元素的输入,mindata的值是在变化的 每次push()入栈一个更小的元素都需要把stack中的差更新一遍吗?
答案是不需要。
试想,当我们引入一个更小的元素value时,它与mindata的差dis = x - mindata显然是个负数,那么这时就要更新mindata=value
那么如果value要出栈的话,stack中保存的是value进栈之前与上一个mindata的差,这时只要将mindata= mindata-value就可以将mindata回退到value入栈之前的最小值。

栈中值为负数的时候 top 和pop都需要特殊判断
#includeclass Solution {
    stackdata;//残差法,维护一个数据栈(记录每个元素与最小值差)
    int mindata;//和一个最小值
public:
    void push(int value) {
        if(data.size()==0)//如果当前栈为空
            mindata=value;//更新当前最小值
        data.push(value-mindata);//数据栈入栈
        if(value-mindata<0)//入栈值小于等于最小值 mindata=value;//更新当前最小值 } void pop() { if(0>=data.top())//如果出栈是当前的最小值 
            mindata=mindata-data.top();//最小值更新
        data.pop();//数据栈出栈
    }
    int top() {
        if(0>=data.top())//如果出栈是当前的最小值 
            return mindata;//返回最小值
        else
            return mindata+data.top();//返回数据栈栈顶元素
    }
    int min() {
        return mindata;//返回最小值
    }
};

  • 时间复杂度: O(1)
  • 空间复杂度: O(1),只需要一个额外的空间维护mindata即可。
  • 运行时间3ms 占用内存492KB

总结

栈的特点是后进先出 前面的数据在后面的数据处理完之前无需更改
需要利用栈的特性