题目
数据流中的中位数
一、思路
数据是流式的从数据容器中读取出来的,如果我们将它存储到一个数组中,需要查找中位数的时候,排序并查找,则排序需要的时间理想是O(logn),查找需要的时间O(1)。
如果将流式的数据存储到排序的数组中,插入需要O(n)的时间,但是查找需要O(1)。
思考一下中位数的特点。
中位数的左边数字均小于中位数。
中位数的右边数字均大于中位数。
中位数左右两边的数字数量相等(偶数个长度的时候中位数取中间2位的平均值)
因此如果我们在读取流式数据的时候,维护两个堆。
一个小顶堆存储右半部分大于中位数的数据。
一个大顶堆存储左半部分小于中位数的数据。
当左右两个顶堆的长度相同时,插入左边的大顶堆。
当左右两个顶堆的长度不同时,插入右边的小顶堆。
基于这个思路需要思考更细致的地方:
1.如果两个顶堆长度相同,需要插入左边,但此时插入的数据大于右边小顶堆的最小值,则这个值应该插入右边的小顶堆,并把右边小顶堆的最小值推入左边大顶堆。
2.如果两个顶堆长度相同,需要插入右边,但此时插入的数据小于左边大顶堆的最大值,则这个值应该插入左边的大顶堆,并把左边大顶堆的最大值推入右边的小顶堆。
class MedianFinder(object):
def __init__(self):
"""
initialize your data structure here.
"""
# 保存左半部分的最大堆
self.left = []
# 保存右半部分的最小堆
self.right = []
def addNum(self, num):
"""
:type num: int
:rtype: None
"""
if len(self.left) == len(self.right):
heapq.heappush(self.right, num)
heapq.heappush(self.left, -heapq.heappop(self.right))
else:
heapq.heappush(self.left, -num)
heapq.heappush(self.right, -heapq.heappop(self.left))
def findMedian(self):
"""
:rtype: float
"""
if len(self.left) == 0:
return 0
if len(self.left) == len(self.right):
mid = (self.right[0] - self.left[0]) / 2.0
else:
mid = -self.left[0]
return mid