Description:
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- getMin() – Retrieve the minimum element in the stack.
My Solution:
-
最先想到用两个栈(栈A栈B),当A栈非空时,以A栈栈顶为基准,大于或等于A栈栈顶的数字push进B栈,小于A栈栈顶的数字push进A栈。
这个方法遇到了两个问题:
(1)分开来push的话进栈的相对顺序就乱了,会给pop()方法带来问题,所以不管数字push进哪一个栈,同时也要给另一个栈push,另一个栈的push的内容要是一个不可能出现的值,这样可以保留相对位置
(2)由第一个问题的解决方案带来的第二个问题,要getMin的时候肯定是去栈A找,但栈A的栈顶很有可能是我为了保持相对位置而push进去的那个“不可能出现的值” -
第二个问题难以解决,于是重新想了办法,仍旧是用两个栈,栈A就用作普通栈,栈B专门用来存相对较小值,当栈A非空时,若push的值小于栈A的栈顶值,就同时将这个值push进两个栈,那么栈B里面从栈顶到栈底就是压栈过程中不同时刻的最小值都保存了(并且有顺序)
代码如下:
class MinStack {
Stack<Integer> stack1;
Stack<Integer> stack2;
/** initialize your data structure here. */
public MinStack() {
this.stack1 = new Stack<>();
this.stack2 = new Stack<>();
}
public void push(int x) {
if (stack2.isEmpty() || stack2.peek() >= x){
stack2.push(x);
}
stack1.push(x);
}
public void pop() {
/*if(stack1.peek() == stack2.peek()){
stack2.pop();
}
stack1.pop();*/
//注意这里!为什么不能用上面注释掉的代码(见summary and knowledge)
int tmp = stack2.peek();
if (stack1.peek() == tmp) {
stack2.pop();
}
stack1.pop();
}
public int top() {
return stack1.peek();
}
public int getMin() {
return stack2.peek();
}
}
Other Solutions:
- 只用一个栈,另用一个int型成员变量来存最小值:
(最初看到这个方法的时候想到一个问题,如果我把最小值pop出去了,只有一个int型变量的话我怎么找到原最小值删除之后的最小值呢?下面的code中的解决方法是每次在找到新的最小值的时候都把原来的最小值重新入栈一次,那么若pop的值正好为当前最小值时,pop之后的栈顶就应该是删除当前最小值后所有值中的最小值)
class MinStack {
int min = Integer.MAX_VALUE;
Stack<Integer> stack = new Stack<Integer>();
public void push(int x) {
// only push the old minimum value when the current
// minimum value changes after pushing the new value x
if(x <= min){
stack.push(min);
min=x;
}
stack.push(x);
}
public void pop() {
// if pop operation could result in the changing of the current minimum value,
// pop twice and change the current minimum value to the last minimum value.
if(stack.pop() == min) min=stack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return min;
}
}
Summary and Knowledge
- 做这题的时候存在审题不清的情况,getMin()方法究竟是只要返回最小值,还是返回最小值并删除栈中的最小值?(但是想想easy题也不会要删除,尤其还要求要常数时间的复杂度
- 为什么pop()方法不能用被注释掉的那些代码:
在reference第一个网址中提到的,peek()返回的是object类型,但其实这是jdk1.4之前的了,1.5之后peek()方法返回的就是其stack中存的item的类型(如该题中的Integer),问题主要是出在返回的类型是普通对象类型Integer,而不是primitive type中的int类型,此时我们拿到的是引用而不是具体的值,用“==”只会比较他们是否指向同一块内存,自然不可。
Reference
https://www.cnblogs.com/grandyang/p/4091064.html
https://stackoverflow.com/questions/3637936/java-integer-equals-vs
https://leetcode.com/problems/min-stack/discuss/49014/Java-accepted-solution-using-one-stack