题目难度: 困难
今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~
随机产生数字并传递给一个方法。你能否完成这个方法,在每次产生新值时,寻找当前所有值的中间值(中位数)并保存。
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
O(logN): 查询和插入都只需要常数次堆操作, 复杂度为 O(logN)O(N): 两个堆共需要存 N 个元素import heapq
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
# 使用两个堆, 左边大顶堆, 右边小顶堆
# 注意python内置的heapq是小顶堆
# 所以大顶堆的话需要将其值取相反数再插入, 也不要忘了pop的时候也要再取反回来
self.left = []
self.right = []
def addNum(self, num: int) -> None:
if len(self.left) == len(self.right):
# 左堆需要增加一个元素
if not self.left or num <= self.right[0]:
# 左堆不存在, 或者新元素不大于右堆顶, 插到左边大顶堆
heapq.heappush(self.left, -num)
else:
# 否则先把右堆顶插到左边, 然后右堆再插入新元素
heapq.heappush(self.left, -heapq.heappop(self.right))
heapq.heappush(self.right, num)
else:
# 右堆需要增加一个元素
# 根据插入逻辑, 此时左堆至少有一个元素, 可以直接拿到左堆顶
if num >= -self.left[0]:
# 新元素不小于左堆顶, 直接插到右边小顶堆即可
heapq.heappush(self.right, num)
else:
# 否则先把左堆顶插到右边, 然后左堆再插入新元素
heapq.heappush(self.right, -heapq.heappop(self.left))
heapq.heappush(self.left, -num)
def findMedian(self) -> float:
if len(self.left) == len(self.right):
# 偶数个元素, 取两个堆顶的平均值
return (-self.left[0] + self.right[0]) / 2
else:
# 奇数个元素, 左堆个数至少为1, 取左堆顶
return -self.left[0]
大家可以在下面这些地方找到我~😊
我的公众号: 算法精选, 欢迎大家扫码关注~😊
