解题思路:(1)在添加元素的过程中保持数组的有序,于是把这个问题抽象成插入排序,每次从头遍历查找插入的位置,直接这样导致超时,于是想到将插入的数和中位数作比较,这样每次可以少遍历一半的数据,测试通过
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.data = []
self.size = 0
def addNum(self, num: int) -> None:
if self.size == 0:
self.data = [num]
self.size += 1
return
if num < self.data[self.size // 2]:
i = 0
while(i < self.size // 2 and self.data[i] < num):
i += 1
else:
i = self.size // 2
while(i < self.size and self.data[i] < num):
i += 1
self.data.insert(i, num)
self.size +=1
def findMedian(self) -> float:
return (self.data[self.size // 2] + self.data[(self.size - 1) // 2]) / 2
(2)上面的方法效率依旧不是很高,可以将查找用二分查找代替
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.data = []
self.size = 0
def addNum(self, num: int) -> None:
left, right = 0, self.size
while(left < right):
mid = left + (right - left) // 2
if self.data[mid] < num:
left = mid + 1
else:
right = mid
self.data.insert(left, num)
self.size +=1
def findMedian(self) -> float:
return (self.data[self.size // 2] + self.data[(self.size - 1) // 2]) / 2
(3)上面的方法查找效率得到了提高,但是插入的时间复杂度依旧和数组长度成正比,下面优化插入的时间复杂度,可以用小顶堆来存储一半(n为奇数,存储n//2+1
,n为偶数存储n//2
)更大的数,用大顶推存储一半(n为奇数,存储n//2-1
,n为偶数存储n//2
)更小的数。算法流程为:(1)当大顶堆和小顶堆元素一样多时,需要向小顶堆插入元素,将要添加的元素插入大顶堆然后弹出大顶堆的堆顶插入到小顶堆中(2)如果此时元素个数不相等,需要向大顶推插入元素,将要添加的元素插入到小顶堆然后弹出小顶堆的堆顶插入到大顶堆中
(3)去中位数时,两个堆元素个数相等取两个堆的堆顶取平均值,不相等时取小顶堆的堆顶返回
from heapq import *
class MedianFinder:
def __init__(self):
"""
initialize your data structure here.
"""
self.bigger = [] #储存n//2 或者 n//2+1个元素
self.smaller = [] #储存n//2或者 n//2+1个元素
def addNum(self, num: int) -> None:
if len(self.bigger) == len(self.smaller):
heappush(self.bigger, -heappushpop(self.smaller, -num))
else:
heappush(self.smaller, -heappushpop(self.bigger, num))
def findMedian(self) -> float:
if len(self.bigger) == len(self.smaller):
return (self.bigger[0] - self.smaller[0]) / 2
else:
return self.bigger[0]