题目
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.
Example:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> Returns -3.
minStack.pop();
minStack.top(); --> Returns 0.
minStack.getMin(); --> Returns -2.
思路
初始思路很偷懒,别的操作都好说,getmin的时候for循环查最短的元素。当然,会超时。看了下超时的用例,主要是一直在调用getmin,所以我将min的查询放到了push和pop中,getmin的时候直接return min。
代码
class MinStack(object):
stack = []
Min = False
Minindex = False
def __init__(self):
"""
initialize your data structure here.
"""
self.stack = []
self.Min = False
self.Minindex = False
def push(self, x):
"""
:type x: int
:rtype: void
"""
self.stack += [x]
if type(self.Min) == type(False) or self.Min > x:
self.Min = x
self.Minindex = len(self.stack) - 1
def pop(self):
"""
:rtype: void
"""
if self.stack:
self.stack = self.stack[:-1]
if not self.stack:
self.Min = False
self.Minindex = False
elif type(self.Minindex) != type(False) and self.Minindex == len(self.stack):
Min = self.stack[0]
minIndex = 0
for index, i in enumerate(self.stack):
if Min > i:
Min = i
minIndex = index
self.Min = Min
self.Minindex = minIndex
def top(self):
"""
:rtype: int
"""
if self.stack:
return self.stack[-1]
def getMin(self):
"""
:rtype: int
"""
if self.stack:
return self.Min
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(x)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
过是过了,但是最佳算法肯定不是这么搞的呀!遂看了下discussion,发现以下几个有趣的算法。
代码一(作者reeclapple)
public class MinStack {
long min;
Stack<Long> stack;
public MinStack(){
stack=new Stack<>();
}
public void push(int x) {
if (stack.isEmpty()){
stack.push(0L);
min=x;
}else{
stack.push(x-min);//Could be negative if min value needs to change
if (x<min) min=x;
}
}
public void pop() {
if (stack.isEmpty()) return;
long pop=stack.pop();
if (pop<0) min=min-pop;//If negative, increase the min value
}
public int top() {
long top=stack.peek();
if (top>0){
return (int)(top+min);
}else{
return (int)(min);
}
}
public int getMin() {
return (int)min;
}
}
这个算法的好处在于push的时候存x - min,如果结果小于0就更新min,pop的时候如果pop值小于0就更新min值,就可以恢复到除去pop值的min值。最后getmin的时候直接输出min值即可,不用遍历list
代码二(作者leftpeter2)
class MinStack
{
static class Element
{
final int value;
final int min;
Element(final int value, final int min)
{
this.value = value;
this.min = min;
}
}
final Stack<Element> stack = new Stack<>();
public void push(int x) {
final int min = (stack.empty()) ? x : Math.min(stack.peek().min, x);
stack.push(new Element(x, min));
}
public void pop()
{
stack.pop();
}
public int top()
{
return stack.peek().value;
}
public int getMin()
{
return stack.peek().min;
}
}
这个算法更精巧,完全不用计算。只需更改下存入的数据结构。如代码所示,该数据结构中带有min值,存入x的时候同时会将当前的min值存入。这样的好处是无论何时,栈顶元素的min值肯定是当前栈的min值,而当元素pop出去后也不用重新计算新的min值,因为除去pop的那个元素后当前的min值还在栈顶的min中。
代码三(作者sometimescrazy)
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;
}
}
这个答案也很不错,存x的时候如果要更新min值,就将min值也存入stack中,pop的时候如果pop值等于min,则min等于stack再次pop出来的值。总的来说就是min值更新的时候将之前的min值也存入stack中,pop的是min值时则恢复之前的min值。缺点就是最坏情况的时候空间占用会比较多。
总结
学到了3种有意思的算法,收获不少,以后也要每做一题都看看discussion学习学习。