题目描述
请定义一个队列并实现函数 max_value 得到队列里的最大值,要求函数max_value、push_back 和 pop_front 的时间复杂度都是O(1)。
若队列为空,pop_front 和 max_value 需要返回 -1
算法思路
NAIVE
class MaxQueue:
def __init__(self):
self.ls=[]
def max_value(self) -> int:
if not self.ls:return -1
return max(self.ls)
def push_back(self, value: int) -> None:
self.ls.append(value)
def pop_front(self) -> int:
if not self.ls:return -1
else:return self.ls.pop(0)
直接使用python内置数据结构列表来完成,都不满足题目要求的时间复杂度,
NAIVE版本的pop和max都是O(n)级别。
纯属偷鸡。不提倡
执行用时 :272 ms, 在所有 Python3 提交中击败了64.64%的用户
内存消耗 :17 MB, 在所有 Python3 提交中击败了100.00%的用户
IMPROVE
push_back 和 pop_front 的时间复杂度都是O(1),恕我才疏学浅,列表是没办法实现push和pop都做到时间复杂度O(1)的吧?所以只能去评论区打开思路了,话说回来居然有人看不懂这次的题,也是比较神奇。
这里参见参考11的思路:使用辅助数组
再提一句,python里的deque数据结构可以实现pop(0)的时间复杂度为O(1),这里先不展开谈。
只考虑辅助数组。
对数组队列queue,直接先进先出即可。
对辅助数组queue_sort,要确保数组最大值在队列首位,那么如何做到?
在push值的过程中,维护辅助数组。
while sort_que and sort_que[-1] < value:
sort_que.pop()
sort_que.append(value)
即push进的value要满足小于sort_que[-1],或辅助列表为空,这样才能把value放入辅助数组。
其实这样说也可能不好理解,那么:
from collections import deque
class MaxQueue:
def __init__(self):
self.queue=deque()
self.queue_sort=deque()
def max_value(self) -> int:
if not self.queue_sort:return -1
return self.queue_sort[0] if self.queue_sort else -1
def push_back(self, value: int) -> None:
self.queue.append(value)
while self.queue_sort and self.queue_sort[-1]<value:
self.queue_sort.pop()
self.queue_sort.append(value)
def pop_front(self) -> int:
if not self.queue:return -1
value=self.queue.popleft()
if value==self.queue_sort[0]:self.queue_sort.popleft()
return value
执行用时 :268 ms, 在所有 Python3 提交中击败了68.78%的用户
内存消耗 :17 MB, 在所有 Python3 提交中击败了100.00%的用户
看到这个执行时间有点尴尬。
至于时间复杂度的问题。
deque使得pop(0)的时间复杂度为O(1)。相关参考:deque详解
而push方法中对辅助数组的操作,因为所有的元素都只会进出一次辅助数组,所以平均时间复杂度是O(1)。
deque详解2
本来想找到deque的源代码的,结果这是用CPython的C代码实现的,集合python模块只是导入了该名称。名为_collections.so
或的文件,_collectionsmodule.so
该文件具有真正的实现,但是我没找到。
退而求其次,只求弄明白操作方式。于是在官方网站找到了详情。
class collections.deque([iterable[, maxlen]])
返回一个新的双向队列对象,从左到右初始化(用方法 append()) ,从 iterable (迭代对象) 数据创建。如果 iterable 没有指定,新队列为空。
Deque 支持线程安全,内存高效添加(append)和弹出(pop),从两端都可以,两个方向的大概开销都是 O(1) 复杂度。
如果 maxlen 没有指定或者是 None ,deques 可以增长到任意长度。否则,deque就限定到指定最大长度。一旦限定长度的deque满了,当新项加入时,同样数量的项就从另一端弹出。
——————
基础方法详情:
方法 | 解释 | 备注 |
---|---|---|
append(x) | 添加 x 到右端。 | |
appendleft(x) | 添加 x 到左端。 | |
clear() | 移除所有元素,使其长度为0. | |
copy() | 创建一份浅拷贝。 | 3.5 新版功能. |
count(x) | 计算 deque 中元素等于 x 的个数。 | 3.2 新版功能. |
extend(iterable) | 扩展deque的右侧,通过添加iterable参数中的元素。 | |
extendleft(iterable) | 扩展deque的左侧,通过添加iterable参数中的元素。 | 左添加时,在结果中iterable参数中的顺序将被反过来添加。 |
index(x[, start[, stop]]) | 返回 x 在 deque 中的位置(索引 start 到stop 之间)。 返回第一个匹配项,如果未找到则引发 ValueError。 | 3.5 新版功能. |
insert(i, x) | 在位置 i 插入 x 。 | 如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。3.5 新版功能. |
pop() | 移去并且返回一个元素,deque 最右侧的那一个。 | 如果没有元素的话,就引发一个 IndexError。 |
popleft() | 移去并且返回一个元素,deque 最左侧的那一个。 | 如果没有元素的话,就引发 IndexError。 |
remove(value) | 移除找到的第一个 value。 如果没有的话就引发 ValueError。 | |
reverse() | 将deque逆序排列。返回 None 。 | 3.2 新版功能. |
rotate(n=1) | 向右循环移动 n 步。 如果 n 是负数,就向左循环。 | deque非空时,向右循环移动一步等价 d.appendleft(d.pop()) ,左循环一步等价 d.append(d.popleft()) 。 |