【堆】Leetcode 295. 数据流的中位数【困难】

数据流的中位数

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。

  • 例如 arr = [2,3,4] 的中位数是 3 。
  • 例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。

实现 MedianFinder 类:

  • MedianFinder() 初始化 MedianFinder 对象。

  • void addNum(int num) 将数据流中的整数 num 添加到数据结构中。

  • double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10 -5次方 以内的答案将被接受。

示例 1:

输入

"MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"

\[\], \[1\], \[2\], \[\], \[3\], \[\]

输出

null, null, null, 1.5, null, 2.0

解释

MedianFinder medianFinder = new MedianFinder();

medianFinder.addNum(1); // arr = [1]

medianFinder.addNum(2); // arr = [1, 2]

medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)

medianFinder.addNum(3); // arr[1, 2, 3]

medianFinder.findMedian(); // return 2.0

解题思路

  • 1、使用两个优先队列(PriorityQueue),一个最大堆用于存储数据流的前半部分,一个最小堆用于存储数据流的后半部分。
  • 2、维护两个堆,使得最大堆的大小等于或比最小堆的大小大1,这样中位数就可以直接从堆顶元素中获取。
  • 3、当新的元素加入数据流时,根据元素的大小,将其插入到最大堆或最小堆中,并调整两个堆,使得满足上述条件。

Java实现

java 复制代码
 private PriorityQueue<Integer> maxHeap; // 存储较小一半的元素
    private PriorityQueue<Integer> minHeap; // 存储较大一半的元素

    public MedianFinder() {
        maxHeap = new PriorityQueue<>(Collections.reverseOrder());
        minHeap = new PriorityQueue<>();
    }
    
    public void addNum(int num) {
        if (maxHeap.isEmpty() || num <= maxHeap.peek()) {
            maxHeap.offer(num);
        } else {
            minHeap.offer(num);
        }
        
        // 平衡两个堆,使大堆的size == 小堆的size 或者 小堆的size+1
        if (maxHeap.size() > minHeap.size() + 1) {
            minHeap.offer(maxHeap.poll());
        } else if (minHeap.size() > maxHeap.size()) {
            maxHeap.offer(minHeap.poll());
        }
    }
    
    public double findMedian() {
        if (maxHeap.isEmpty() && minHeap.isEmpty()) {
            return 0;
        }
        
        if (maxHeap.size() == minHeap.size()) {
            return (maxHeap.peek() + minHeap.peek()) / 2.0;
        } else {
            return maxHeap.peek();
        }
    }

时间空间复杂度

  • 时间复杂度:

addNum方法的时间复杂度为O(log n),其中n为数据流中元素的个数,因为在插入元素时需要维护堆的平衡。

findMedian方法的时间复杂度为O(1),因为只需要获取堆顶元素即可。

  • 空间复杂度:

由于使用了两个优先队列,所以空间复杂度为O(n)。

相关推荐
水木流年追梦11 分钟前
大模型入门-应用篇3-Agent智能体
开发语言·python·算法·leetcode·正则表达式
洛水水20 分钟前
【力扣100题】31.二叉树的层序遍历
算法·leetcode·职场和发展
君义_noip26 分钟前
CSP-S 2025 入门级 第一轮(初赛) 完善程序(1)
c++·算法·信息学奥赛·初赛·csp 第一轮
洛水水29 分钟前
【力扣100题】41.爬楼梯
算法·leetcode·职场和发展
Pkmer1 小时前
LeetCode 上极少见的工程级滑窗实现
python·leetcode
sheeta19982 小时前
LeetCode 每日一题笔记 日期:2026.05.13 题目:1674. 使数组互补的最少操作次数
笔记·算法·leetcode
liulilittle2 小时前
TCP UCP v1.0:BBR 的非破坏性约束层
网络·c++·网络协议·tcp/ip·算法·c·通信
每天回答3个问题2 小时前
LeetCodeHot100|回溯算法、46.全排列、78.子集、17.电话号码的字母组合
算法·深度优先·回溯
YL200404262 小时前
038翻转二叉树
数据结构·leetcode
Liangwei Lin3 小时前
LeetCode 287. 寻找重复数
算法·leetcode·职场和发展