优质博文:IT-BLOG-CN
一、题目
设计一个支持push
,pop
,top
操作,并能在常数时间内检索到最小元素的栈。
实现MinStack
类:
MinStack()
初始化堆栈对象。
void push(int val)
将元素val
推入堆栈。
void pop()
删除堆栈顶部的元素。
int top()
获取堆栈顶部的元素。
int getMin()
获取堆栈中的最小元素。
示例 1:
输入:["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
.
-231 <= val <= 231 - 1
pop、top
和getMin
操作总是在非空栈上调用
push, pop, top, and getMin
最多被调用3 * 104
次
二、代码
辅助栈: 对于栈,如果一个元素a
在入栈时,栈里有其它的元素b, c, d
,那么无论这个栈在之后经历了什么操作,只要a
在栈中,b, c, d
就一定在栈中,因为在a
被弹出之前,b, c, d
不会被弹出。因此,在操作过程中的任意一个时刻,只要栈顶的元素是a
,那么我们就可以确定栈里面现在的元素一定是a, b, c, d
。那么,我们可以在每个元素a
入栈时把当前栈的最小值m
存储起来。在这之后无论何时,如果栈顶元素是a
,我们就可以直接返回存储的最小值m
。
按照上面的思路,我们只需要设计一个数据结构,使得每个元素a
与其相应的最小值m
时刻保持一一对应。因此我们可以使用一个辅助栈,与元素栈同步插入与删除,用于存储与每个元素对应的最小值。
【1】当一个元素要入栈时,我们取当前辅助栈的栈顶存储的最小值,与当前元素比较得出最小值,将这个最小值插入辅助栈中;
【2】当一个元素要出栈时,我们把辅助栈的栈顶元素也一并弹出;
【3】在任意一个时刻,栈内元素的最小值就存储在辅助栈的栈顶元素中。
class MinStack {Deque<Integer> xStack;Deque<Integer> minStack;public MinStack() {xStack = new LinkedList<Integer>();minStack = new LinkedList<Integer>();minStack.push(Integer.MAX_VALUE);}public void push(int x) {xStack.push(x);minStack.push(Math.min(minStack.peek(), x));}public void pop() {xStack.pop();minStack.pop();}public int top() {return xStack.peek();}public int getMin() {return minStack.peek();}
}
时间复杂度: 对于题目中的所有操作,时间复杂度均为O(1)
。因为栈的插入、删除与读取操作都是O(1)
,我们定义的每个操作最多调用栈操作两次。
空间复杂度: O(n)
,其中n
为总操作数。最坏情况下,我们会连续插入n
个元素,此时两个栈占用的空间为O(n)
。