LeetCode上有两道关于Stack的题目:
其中MinStack有个变体题目是MinQueue,简单地来说就是要实现Queue的常用操作,并使获取Queue中的最小值操作所需的时间复杂度为常数。
由于直接套MinStack的Solution在MinQueue上是行不通的,因此可以先实现MinStack,再用MinStack实现Queue。
MinStack
Problem 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.
Solution
解法有两种,但是核心思想都是利用空间换时间。
Solution A
在原有的栈的基础上,再维护一个存放最小值索引的栈。
For Example:
Talk is cheap, show code.
class MinStack(object):
def __init__(self):
self.index_stack = []
self.data_stack = []
def pop(self):
"""
判断出栈值是否为最小索引栈的top值,如果是,最小索引栈也执行pop操作
:return:
"""
o = self.data_stack[-1]
if o == self.data_stack[self.index_stack[-1]]:
self.index_stack.pop()
return self.data_stack.pop()
def push(self, o):
"""
判断入栈值是否比最小索引栈的top值小,如果是,入栈值的索引入栈
:param o: 入栈值
:return:
"""
index = None
if not self.index_stack:
index = 0
elif o <= self.data_stack[self.index_stack[-1]]:
index = len(self.data_stack)
if index is not None:
self.index_stack.append(index)
self.data_stack.append(o)
def top(self):
return self.data_stack[-1]
def getMin(self):
if not self.data_stack:
raise IndexError("get min from empty list")
index = self.index_stack[-1]
return self.data_stack[index]
Solution B
利用链表的思想,入栈时同时保存当前最小值的信息。
For Example:
from collections import namedtuple
StackNode = namedtuple("StackNode", ["value", "curr_min"])
class MinStack(object):
def __init__(self):
self.data_stack = []
def pop(self):
return self.data_stack.pop().value
def push(self, o):
"""
当前栈的top值小于入栈值时,即将入栈的最小值才为上一个最小值,否则为
入栈值(包括栈中没有元素以及,入栈值大于上一个最小值的情况)
:param o: 入栈值
:return:
"""
min_value = o
if self.data_stack and o > self.getMin():
min_value = self.getMin()
self.data_stack.append(StackNode(value=o, curr_min=min_value))
def top(self):
return self.data_stack[-1].value
def getMin(self):
return self.data_stack[-1].curr_min
Implement Queue using Stacks
Problem Description
Implement the following operations of a stack using queues.
- push(x) – Push element x onto stack.
- pop() – Removes the element on top of the stack.
- top() – Get the top element.
- empty() – Return whether the stack is empty.
Solution
通过两个栈来实现一个队列,push_stack执行队列的入队操作,pop_stack执行队列的出队操作。
当执行入队操作的时候,push_stack可以视为LIFO顺序;当执行出队操作的时候,需要将push_stack中的元素弹出,并push进pop_stack,此时pop_stack中的元素出栈顺序就可以视为是正常队列的FIFO顺序。
For Example:
class MockQueue(object):
def __init__(self):
self.push_stack = []
self.pop_stack = []
def _clear_push_stack(self):
while self.push_stack:
self.pop_stack.append(self.push_stack.pop())
def push(self, o):
self.push_stack.append(o)
def pop(self):
if not self.pop_stack:
self._clear_push_stack()
return self.pop_stack.pop()
def peek(self):
if not self.pop_stack:
self._clear_push_stack()
return self.pop_stack[-1]
def empty(self):
return not bool(self.push_stack or self.pop_stack)
注意pop操作只有在pop_stack为空的情况下才需要clear_push_stack。
MinQueue
题目的要求之前已经说的很清楚了,直接上代码。
# implement queue using stacks + min stack = min queue
class MinQueue(object):
def __init__(self):
self.push_stack = MinStack()
self.pop_stack = MinStack()
def _clear_push_stack(self):
while not self.push_stack.empty():
self.pop_stack.push(self.push_stack.pop())
def push(self, o):
self.push_stack.push(o)
def pop(self):
if self.pop_stack.empty():
self._clear_push_stack()
return self.pop_stack.pop()
def peek(self):
if self.pop_stack.empty():
self._clear_push_stack()
return self.pop_stack.top()
def empty(self):
return self.push_stack.empty() and self.pop_stack.empty()
def getMin(self):
return min([self.push_stack.getMin(), self.pop_stack.getMin()])