题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。
示例:
MinStack minStack = new MinStack(); minStack.push(-2); minStack.push(0); minStack.push(-3); minStack.min(); --> 返回 -3. minStack.pop(); minStack.top(); --> 返回 0. minStack.min(); --> 返回 -2.
提示:
- 各函数的调用总次数不超过 20000 次
本题的关键点是如何将min操作的时间复杂度降到O(1),难点在于栈中的元素是动态的,随着元素的出栈,最小值一直在变化。
为了记录最小值的变化,我们引入另一个辅助栈。在入栈时如果要入栈的值比辅助栈顶的元素更小,那么就同时将这个值压入辅助站中。在出栈时,如果当前出栈的值比辅助栈顶的元素大,那么辅助栈就无须变化,否则就需要将辅助栈顶的元素弹出。
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack=[]
self.min_num=[]
def push(self, x):
"""
:type x: int
:rtype: None
"""
self.stack.append(x)
if len(self.min_num) == 0 or self.min_num[-1]>=x:
self.min_num.append(x)
def pop(self):
"""
:rtype: None
"""
if self.min_num[-1] == self.stack[-1]:
self.min_num.pop()
self.stack.pop()
def top(self):
"""
:rtype: int
"""
return self.stack[-1]
def min(self):
"""
:rtype: int
"""
if len(self.min_num) == 0:
return None
return self.min_num[-1]
上面这种做法是较为容易想到的,还有另一种非常巧妙不引入额外空间的方法,只有一个栈和栈当前最小值的变量,但是比较难理解。
入栈时首先计算原数值与当前栈中最小值的差值,这个差值如果是正数就表示原数值比较大,直接将差值入栈。如果是负数就表示原数值更小,则差值入栈后要将当前最小值更新为原数值。也就是说栈中保存的是原数值与此前栈中最小值的差值,在差值入栈之后要更新最小值。
入栈(不更新最小值):原数值 - 最小值 = 入栈值
入栈(更新最小值):原数值 - 前最小值 = 入栈值
要注意公式中的最小值,这个最小值在入栈操作完成后会更新,也就是说入栈值是由入栈前的栈最小值计算得到的,如果入栈操作后更新了最小值,那么入栈值加当前最小值并不等于原数值,因为当前最小值本身就是原数值。
求栈顶元素时首先判断栈顶入栈值是正数还是负数,如果是正数则表示原数值不是最小值,那么就将最小值与这个差值相加即可。如果是负数则表示这个位置原本的数就是当前最小值,那么就直接返回当前最小值。
原数值还原:原数值 = 最小值 + 入栈值
出栈时,如果栈顶入栈值是正数 ,那么表示原数值不是最小值,弹出后最小值不会发生变化。如果是负数,那么表示原数值就是栈最小值,将它弹出后要更新最小值。前面说过,如果原数值是最小值,那么入栈的公式是:原数值 - 前最小值 = 入栈值。而入栈后会将最小值更新为原数值。也就是:当前最小值 - 前最小值 = 入栈值,那么我们就可以得到:
最小值还原:前最小值 = 当前最小值 - 入栈值
这种方法真的很绕,建议自己手动模拟几次入站出站操作,代码如下:
class MinStack(object):
def __init__(self):
"""
initialize your data structure here.
"""
self.stack=[]
self.min_num=float('inf')
def push(self, x):
"""
:type x: int
:rtype: None
"""
if len(self.stack) == 0:
self.stack.append(0)
self.min_num=x
else:
self.stack.append(x-self.min_num)
self.min_num=min(x,self.min_num)
def pop(self):
"""
:rtype: None
"""
top=self.stack.pop()
if top < 0:
self.min_num-=top
def top(self):
"""
:rtype: int
"""
top=self.stack[-1]
if top >=0:
return self.min_num+top
else:
return self.min_num
def min(self):
"""
:rtype: int
"""
return self.min_num