栈题目:最小栈

题目

标题和出处

标题:最小栈

出处:155. 最小栈

难度

4 级

题目描述

要求

设计一个支持入栈、出栈、查看栈顶元素操作,并能在常数时间内检索到最小元素的栈。

实现 MinStack \texttt{MinStack} MinStack 类:

  • MinStack() \texttt{MinStack()} MinStack() 初始化栈对象。
  • void   push(val) \texttt{void push(val)} void push(val) 将元素 val \texttt{val} val 入栈。
  • void   pop() \texttt{void pop()} void pop() 删除栈顶的元素。
  • int   top() \texttt{int top()} int top() 获取栈顶元素。
  • int   getMin() \texttt{int getMin()} int getMin() 检索栈内的最小元素。

示例

示例 1:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"] \texttt{["MinStack","push","push","push","getMin","pop","top","getMin"]} ["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]] \texttt{[[],[-2],[0],[-3],[],[],[],[]]} [[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2] \texttt{[null,null,null,null,-3,null,0,-2]} [null,null,null,null,-3,null,0,-2]
解释:
MinStack   minStack   =   new   MinStack(); \texttt{MinStack minStack = new MinStack();} MinStack minStack = new MinStack();
minStack.push(-2); \texttt{minStack.push(-2);} minStack.push(-2);
minStack.push(0); \texttt{minStack.push(0);} minStack.push(0);
minStack.push(-3); \texttt{minStack.push(-3);} minStack.push(-3);
minStack.getMin(); \texttt{minStack.getMin();} minStack.getMin(); // 返回 -3 \texttt{-3} -3
minStack.pop(); \texttt{minStack.pop();} minStack.pop();
minStack.top(); \texttt{minStack.top();} minStack.top(); // 返回 0 \texttt{0} 0
minStack.getMin(); \texttt{minStack.getMin();} minStack.getMin(); // 返回 -2 \texttt{-2} -2

数据范围

  • -2 31 ≤ val ≤ 2 31 − 1 \texttt{-2}^\texttt{31} \le \texttt{val} \le \texttt{2}^\texttt{31} - \texttt{1} -231val2311
  • 方法 pop \texttt{pop} pop top \texttt{top} top getMin \texttt{getMin} getMin 总是在非空栈上调用
  • 最多调用 3 × 10 4 \texttt{3} \times \texttt{10}^\texttt{4} 3×104 push \texttt{push} push pop \texttt{pop} pop top \texttt{top} top getMin \texttt{getMin} getMin

解法

思路和算法

最小栈需要支持常规栈的操作,另外还要在常数时间内检索到最小元素。为了支持常规栈的操作,需要维护一个常规栈。为了在常数时间内检索到最小元素,需要维护一个最小元素栈,最小元素栈的栈顶元素为最小元素。常规栈和最小元素栈分别为 stack \textit{stack} stack minStack \textit{minStack} minStack

对于 push \textit{push} push 方法,进行如下操作:

  • 将元素 val \textit{val} val 入栈 stack \textit{stack} stack

  • 如果 minStack \textit{minStack} minStack 为空或者 val \textit{val} val 小于等于 minStack \textit{minStack} minStack 的栈顶元素,则 val \textit{val} val 是最小元素,将 val \textit{val} val 入栈 minStack \textit{minStack} minStack

对于 pop \textit{pop} pop 方法,进行如下操作:

  • stack \textit{stack} stack 的栈顶元素出栈,记为 val \textit{val} val

  • 如果 val \textit{val} val minStack \textit{minStack} minStack 的栈顶元素相等,则出栈的元素是最小元素,将 minStack \textit{minStack} minStack 的栈顶元素出栈。

对于 top \textit{top} top 方法,返回 stack \textit{stack} stack 的栈顶元素。

对于 getMin \textit{getMin} getMin 方法,返回 minStack \textit{minStack} minStack 的栈顶元素。

根据上述操作, minStack \textit{minStack} minStack 的元素个数总是少于或等于 stack \textit{stack} stack 的元素个数,且 minStack \textit{minStack} minStack 是单调栈,栈底到栈顶的元素非严格单调递减。

由于当每次入栈的元素是最小元素时,该元素都会入栈 minStack \textit{minStack} minStack,且 minStack \textit{minStack} minStack 具有单调性,因此在只有 push \textit{push} push 操作的情况下, minStack \textit{minStack} minStack 的栈顶元素一定是最小元素, getMin \textit{getMin} getMin 方法返回的一定是最小元素。

在有 pop \textit{pop} pop 操作的情况下, minStack \textit{minStack} minStack 的栈顶元素也一定是最小元素,理由如下。

根据 push \textit{push} push pop \textit{pop} pop 方法的实现可知, minStack \textit{minStack} minStack 中的每个元素都在 stack \textit{stack} stack 中有一个对应元素,对应元素的含义是,这两个元素(分别属于两个栈)同时入栈和同时出栈。当一个元素从 minStack \textit{minStack} minStack 出栈时,该元素在 stack \textit{stack} stack 中的对应元素同时出栈,此时两个栈内的元素仍然符合最小栈的性质。

下图为题中示例的三次入栈操作的过程。

图 1

下图为题中示例的一次出栈操作的过程。由于 stack \textit{stack} stack 的出栈元素 − 3 -3 3 minStack \textit{minStack} minStack 的栈顶元素相等,因此也将 minStack \textit{minStack} minStack 的栈顶元素出栈。

图 2

代码

class MinStack {
    Deque<Integer> stack;
    Deque<Integer> minStack;

    public MinStack() {
        stack = new ArrayDeque<Integer>();
        minStack = new ArrayDeque<Integer>();
    }
    
    public void push(int val) {
        stack.push(val);
        if (minStack.isEmpty() || val <= minStack.peek()) {
            minStack.push(val);
        }
    }
    
    public void pop() {
        int val = stack.pop();
        if (minStack.peek() == val) {
            minStack.pop();
        }
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

复杂度分析

  • 时间复杂度:构造方法和每一项操作的时间复杂度都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是元素个数。空间复杂度主要取决于栈空间,常规栈和最小元素栈的空间都是 O ( n ) O(n) O(n)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值