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(只会多1,因为每次插入元素都会判断),就直接把小顶堆的堆顶元素移除并加到大顶堆中。

时间复杂度O(log n)

代码:

java 复制代码
class MedianFinder {
    private PriorityQueue<Integer> minHeap;
    private PriorityQueue<Integer> maxHeap;

    public MedianFinder() {
        minHeap = new PriorityQueue<>();
        maxHeap = new PriorityQueue<>(Collections.reverseOrder());
    }
    
    public void addNum(int num) {
        if(!maxHeap.isEmpty() && num < maxHeap.peek()){
            maxHeap.offer(num);
        }else{
            minHeap.offer(num);
        }

        // 平衡两个堆的数量
        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.size() == minHeap.size() + 1){
            return maxHeap.peek();
        }else{
            return (maxHeap.peek() + minHeap.peek()) / 2.0;
        }
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */
相关推荐
Cx330❀29 分钟前
【Linux网络】网络层协议 IP :从网络层原理到 Linux 内核源码
linux·运维·服务器·网络·tcp/ip·ai·ai编程
小荷才露尖尖角,早有蜻蜓立上头38 分钟前
过滤器的4种创建方式
java
大圣编蚕1 小时前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
程序员阿明1 小时前
idea把插件啥的不默认放在C盘
java·ide·intellij-idea
Gl�ria1 小时前
Linux 清理日志常用命令
linux·运维·服务器
mayaairi1 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
linweidong2 小时前
中科闻歌Java面试题及参考答案
java·python·大模型·提示词·ai agent·mcp·rag原理
OpenAnolis小助手2 小时前
一句话看透 JVM,SysOM 诊断 Skill 新增 Java 应用诊断能力
java·开发语言·jvm·阿里云·操作系统控制台·sysom
天道jimmy2 小时前
VulnHub 系列:HA, Wordy
linux·服务器·web安全
kyriewen2 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能