注意审题:要求常数时间(不能用排序算法)。
基本思想:由于题目要求只花费常数时间,故需要借助“以空间换时间”的思想。
初步思考,会想到每次入栈时记录下当前最小值,但是当栈顶元素就是最小值被删除后,当前最小值应该被更新为什么值呢?因此记录当前最小值是不够的,还需要记录之前最小值。
解法一
主要思想
使用辅助栈,在数据入数据栈时即考虑是否放入辅助栈,因此不用在调用getMin函数时重新全部扫描一遍数据栈内的元素,可直接从辅助栈中找到最小元素,花费的是常数时间而不是线性时间。
关键点-辅助栈的入栈与出栈:
当辅助栈为空时,入栈;当待入数据栈的数小于或等于辅助栈栈顶的数时,入栈(该操作保证了辅助栈顶存放的一直都是当前最小的元素,每次入栈时都会新增记录当前最小值,同时保留之前的最小值);
当数据栈栈顶元素要出栈时,如果该元素与辅助栈顶元素相同,则辅助栈栈顶元素也要出栈,因为此时数据栈的最小元素已经出栈(此操作也通过更新辅助栈的栈顶元素,更新了保存的数据栈当前最小的元素);
代码样例
class MinStack:
def __init__(self):
self.stack = []
self.helper = []
def push(self, x: int) -> None:
self.stack.append(x)
if len(self.helper)==0 or x<=self.helper[-1]:
self.helper.append(x)
def pop(self) -> None:
if self.helper[-1] == self.stack.pop():
self.helper.pop()
def top(self) -> int:
return self.stack[-1]
def getMin(self) -> int:
return self.helper[-1]
解法二
主要思想
仅有数据栈,但修改数据结构。存储每个元素时,同时在同一位置存储当前最小值。也就是将 元组(value, min) 作为一个整体存储在栈中。
因此在调用getMin函数时,可以直接获取栈顶元素中的min;
当删除栈顶元素时,剩下的栈顶元素中存储的也是元组(栈顶元素,当前最小值)。
代码样例
class MinStack:
def __init__(self):
self.stack = []
def push(self, x: int) -> None:
if not self.stack:
self.stack.append((x, x))
elif x <= self.stack[-1][1]:
self.stack.append((x, x))
else:
self.stack.append((x, self.stack[-1][1]))
def pop(self) -> None:
return self.stack.pop()[0]
def top(self) -> int:
return self.stack[-1][0]
def getMin(self) -> int:
return self.stack[-1][1]
解法三
只用一个变量(存储当前最小元素)和一个栈(每个元素存储的是当时的栈顶元素与当时最小元素的差值)
入栈:
- 当原本要入栈的元素x比当前最小元素curr_min大时,实际需要入栈的是diff=x-curr_min是一个正数,当前最小值无需更新;
- 当原本要入栈的元素x比当前最小元素curr_min小时,实际需要入栈的是diff=x-curr_min是一个负数,当前最小值更新为x(实际上也等于curr_min=curr_min+diff,这一点很重要,说明了当想要得到上一个最小值时用当前最小值curr_min减去diff即可,每次入栈保存的diff起到了保存过去最小值的作用);
出栈:
- 当要出栈的数是负数时(对应入栈diff为负数的场景),说明当时原本需要入栈的元素x小于当时的当前最小值curr_min,curr_min已更新为出栈的元素curr_min=min(x, curr_min),因此出栈元素x应为curr_min;且出栈后需要更新当前最小值为curr_min=curr_min-diff;
- 当要出栈的数是正数时(对应入栈diff正数的场景),说明原需出栈的元素x大于当前最小值curr_min,还原需要出栈的元素x=diff+curr_min,无需更新当前最小值;
取栈顶元素:每次调用top()或pop()函数时,返回的是栈顶元素的值diff与当前最小值curr_min的和(因为x=diff+curr_min)。
代码样例(有bug。。。会溢出)
class MinStack:
def __init__(self):
self.stack = []
self.curr_min = None
def push(self, x: int) -> None:
if not self.stack:
self.curr_min = x
self.stack.append(x - self.curr_min)
else:
self.stack.append(x - self.curr_min)
self.curr_min = min(self.curr_min, x)
def pop(self) -> None:
if not self.stack:
return None
if self.stack[-1] < 0:
res = self.curr_min
self.curr_min -= self.stack.pop()
else:
res = self.stack.pop() + self.curr_min
return res
def top(self) -> int:
if not self.stack:
return None
if self.stack[-1] < 0:
return self.stack[-1]
else:
return self.stack[-1] + self.curr_min
def getMin(self) -> int:
return self.curr_min