LeetCodeDifficult-【面试题41. 数据流中的中位数】

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

示例 1:
输入:
[“MedianFinder”,“addNum”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[1],[2],[],[3],[]]
输出:[null,null,null,1.50000,null,2.00000]

示例 2:
输入:
[“MedianFinder”,“addNum”,“findMedian”,“addNum”,“findMedian”]
[[],[2],[],[3],[]]
输出:[null,null,2.00000,null,2.50000]

限制:
最多会对 addNum、findMedia进行 50000 次调用。

注意:本题与主站 295 题相同:https://leetcode-cn.com/problems/find-median-from-data-stream/

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-ju-liu-zhong-de-zhong-wei-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路1:二分查找

找中位数就是需要找排序好的list中的中位数,那么就需要对list排序,在每次插入数据后,应该保证list有序,对于一个有序的list,我们插入一个数据的时间复杂度可以为O(n)。包括:二分查找的合适的位置 O(logn),移动数据并插入O(n)。
找中位数就比较简单,分一下奇偶数就行。
在这里插入图片描述

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.nums = []

    def addNum(self, num: int) -> None:
        if self.nums == []:
            self.nums.append(num)
            return 
        def find(l, r, num):
            # 查找第一个不小于num的数的位置
            while l <= r:
                mid = (l + r) // 2 
                if self.nums[mid] < num:
                    l = mid + 1
                else:
                    r = mid - 1
            return l
        x = find(0, len(self.nums) - 1, num)
        # print(self.nums, num, x)
        self.nums = self.nums[0:x] + [num] + self.nums[x:]

    def findMedian(self) -> float:
        length = len(self.nums)
        if length & 1 == 0:
            return (self.nums[length // 2 - 1] + self.nums[length // 2]) / 2
        else:
            return self.nums[length // 2]


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

思路2:大根堆、小根堆

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意思考下,为什么每次打算加入一个堆的数据,必须先放入另一个堆,在弹出该堆的堆顶元素加入预加入的堆中。
在这里插入图片描述

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.A = []  # 大根堆, 存储较小部分,即排序好后的前部分(默认是小根堆,实现大根堆,只需要把数字全部取反就行了)
        self.B = []  # 小根堆,存储较大部分,即排序好后的后部分

    def addNum(self, num: int) -> None:
        if len(self.A) == len(self.B):
            # heapq.heappush(self.B, num)  # 先放入B,得到B的最小值,再放入A中,保证A中的多一个数
            # heapq.heappush(self.A, -heapq.heappop(self.B))
            # 以上两步可以合并为一步:
            heapq.heappush(self.A, -heapq.heappushpop(self.B, num))
        else:
            # heapq.heappush(self.A, -num)  # 先放入A,得到A的最大值的相反数,再放入B中
            # heapq.heappush(self.B, -heapq.heappop(self.A))
            # 以上两步可以合并为一步:
            heapq.heappush(self.B, -heapq.heappushpop(self.A, -num))
        # print(self.A, self.B)
    def findMedian(self) -> float:
        if len(self.A) == len(self.B):
            return (-self.A[0] + self.B[0]) / 2
        else:
            return -self.A[0]

# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ystraw_ah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值