《剑指Offer》刷题笔记——面试题41. 数据流中的中位数

难度:困难

一、题目描述:

在这里插入图片描述

二、解题分析:

1、

使用大根堆和小根堆
  假想我们现在有两个容器 A, B 这两个容器将我们的整体数据分成两部分,且 A 中的数据都小于 B 中的数据,并且 A 中的最后一个数据是 A 里面最大的
  B 的第一个数据是 B 中最小的.
  好了 我们有了上面的条件,那我们怎么找到中位数呢?
  当整体数目为奇数时,中间的那个数就是所求.当整体数目为偶数时,中间两个数的和再除以 2 ,就能得到结果
  但这和我们上面的两个容器有什么关系呢?
  我们只要将上面的两个容器的数据数目只差保持在 1 之内即可,也就是说 A 和 B 将整体数据以中位数划分开来了

#python2
class MedianFinder(object):
    from heapq import *
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.bigHpeap = []
        self.smallHeap = []
    def addNum(self, num):
        """
        :type num: int
        :rtype: None
        """
        if len(self.bigHpeap) == len(self.smallHeap):#总数为偶数时,先插入到大根堆,在插入到小根堆
            heapq.heappush(self.smallHeap, -heapq.heappushpop(self.bigHpeap, -num))
        else:#总数为奇数时,先插入到小根堆,在插入到大根堆
            heapq.heappush(self.bigHpeap, -heapq.heappushpop(self.smallHeap, num))

    def findMedian(self):
        """
        :rtype: float
        """
        if len(self.bigHpeap) == len(self.smallHeap):
            return (-self.bigHpeap[0] + self.smallHeap[0]) / 2.0
        else:
            return self.smallHeap[0]



# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()

2、

此处撰写解题思路
  主要思路:维护一个大根堆和一个小根堆,保证每一时刻操作完后,两个堆中的元素个数差异不超过1,
  1)若当前元素个数相等,则将当前的要插入的数insert到其中一个堆(如大根堆)中,再从该堆(大根堆)中弹出堆顶元素到另一个堆(小根堆)中;
  2)若当前元素个数不等,也就是小根堆比大根堆多1个元素,则将当前的要插入的数insert到小根堆中,再从该堆(小根堆)中弹出堆顶元素到另一个堆(大根堆)中。
  也就是说,保证任意时刻大根堆中所有元素都小于小根堆的堆顶元素,大根堆存储排序后大小占前N/2个数,小根堆存储后N/2个数,中位数就是对应的堆顶元素(如果从数据流中读出奇数个数值,那么中位数就是比另一个数要多一个数的那个堆(这里是小根堆)。如果从数据流中读出偶数个数值,那么中位数就是堆顶两个数的平均值)。

#python3
class SmallRootHeap:
    def __init__(self):
        self.arr = list()
    def get_length(self):
        return len(self.arr)
    def heap_insert(self,num):
        heapq.heappush(self.arr, num)
    def heapify(self):
        heapq.heapify(self.arr)
    def heap_pop(self):
        return heapq.heappop(self.arr)
    def get_top(self):
        if not self.arr:return
        return self.arr[0]

class LargeRootHeap:
    def __init__(self):
        self.arr = list()
    def get_length(self):
        return len(self.arr)
    def heap_insert(self,num):
        heapq.heappush(self.arr,-num)
    def heap_pop(self):
        return -heapq.heappop(self.arr)
    def heapify(self):
        heapq.heapify(self.arr)
    def get_top(self):
        if not self.arr:return
        return -self.arr[0]

class MedianFinder:
    def __init__(self):
        self.smallrootheap, self.largerootheap = SmallRootHeap(),LargeRootHeap()

    def addNum(self,num:int) -> None:
        if self.smallrootheap.get_length() == self.largerootheap.get_length():
            self.largerootheap.heap_insert(num)
            self.smallrootheap.heap_insert(self.largerootheap.heap_pop())
        else:
            self.smallrootheap.heap_insert(num)
            self.largerootheap.heap_insert(self.smallrootheap.heap_pop())

    def findMedian(self) -> float:
        if self.largerootheap.get_length() == self.smallrootheap.get_length():
            return  (self.largerootheap.get_top() + self.smallrootheap.get_top())/2
        else:
            return self.smallrootheap.get_top()

# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
发布了133 篇原创文章 · 获赞 155 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_34108714/article/details/104700791
今日推荐