原题地址(困难)
方法1—优先队列/堆
思路
这题真的太难了
这题是在295题基础之上,难度我感觉又提升了一个level
295. 数据流的中位数
295题是单纯的双优先队列,而这题,又加了 延迟删除 的思想,这是最难的地方。
直接看了官方题解,照着它的思路写了代码。
代码
class DualHeap:
def __init__(self, k: int):
self.maxHeap = []
self.minHeap = []
self.delayed = collections.Counter()
self.k = k
self.maxHeapSize = 0
self.minHeapSize = 0
def prune(self, heap): # 不断删除堆顶元素,更新哈希表,为的是保证堆顶元素是不需要被延迟删除的
while heap:
num = heap[0] # 堆顶元素
if heap is self.maxHeap: # 大顶堆要取反
num = -num
if num in self.delayed: # 这个堆顶元素需要删除
self.delayed[num] -= 1
if self.delayed[num] == 0:
self.delayed.pop(num)
heapq.heappop(heap)
else:
break
def makeBalance(self): # 调整大根堆小根堆的元素个数
if self.maxHeapSize - self.minHeapSize >= 2:
maxHeapTop = -heapq.heappop(self.maxHeap) # 得到堆顶元素
heapq.heappush(self.minHeap, maxHeapTop) # 放入小顶堆
self.maxHeapSize -= 1
self.minHeapSize += 1
self.prune(self.maxHeap)
elif self.minHeapSize > self.maxHeapSize:
minHeapTop = heapq.heappop(self.minHeap)
heapq.heappush(self.maxHeap, -minHeapTop)
self.minHeapSize -= 1
self.maxHeapSize += 1
self.prune(self.minHeap)
def insert(self, num): # 插入
if not self.maxHeap or num <= -self.maxHeap[0]:
heapq.heappush(self.maxHeap, -num)
self.maxHeapSize += 1
else:
heapq.heappush(self.minHeap, num)
self.minHeapSize += 1
self.makeBalance()
def erase(self, num): # 删除
self.delayed[num] += 1
if num <= -self.maxHeap[0]:
self.maxHeapSize -= 1
if num == -self.maxHeap[0]:
self.prune(self.maxHeap)
else:
self.minHeapSize -= 1
if num == self.minHeap[0]:
self.prune(self.minHeap)
self.makeBalance()
def getMedian(self): # 得到中位数
return -self.maxHeap[0] if self.k & 1 else (-self.maxHeap[0] + self.minHeap[0]) / 2
class Solution:
def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]:
dh = DualHeap(k)
for num in nums[:k]: # 初始化
dh.insert(num)
ans = [dh.getMedian()]
for i in range(k, len(nums)):
dh.insert(nums[i])
dh.erase(nums[i-k])
ans.append(dh.getMedian())
return ans
时空复杂度
时间复杂度O(logN)
空间复杂度O(N)