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();
 */
相关推荐
酉鬼女又兒33 分钟前
入门前端CSS 媒体查询全解析:从入门到精通,打造完美响应式布局(可用于备赛蓝桥杯Web应用开发)
前端·css·职场和发展·蓝桥杯·前端框架·html5·媒体
@encryption37 分钟前
TCP,IP
服务器·网络·tcp/ip
Dxy123931021642 分钟前
HTML常用标签详解
前端·html
毛骗导演44 分钟前
@tencent-weixin/openclaw-weixin 插件深度解析(一):认证与会话管理机制
前端·架构
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 鸡场养殖管理系统为例,包含答辩的问题和答案
java
sheji34161 小时前
【开题答辩全过程】以 高校自习室智能化管理系统为例,包含答辩的问题和答案
java
wefly20171 小时前
告别本地环境!m3u8live.cn一键实现 M3U8 链接预览与调试
前端·后端·python·音视频·m3u8·前端开发工具
yaoxin5211231 小时前
358. Java IO API - 使用 relativize() 创建路径之间的相对关系
java·linux·python
SuperEugene1 小时前
前端 console 日志规范实战:高效调试 / 垃圾 log 清理与线上安全避坑|编码语法规范篇
开发语言·前端·javascript·vue.js·安全
发现一只大呆瓜1 小时前
Vue - @ 事件指南:原生 / 内置 / 自定义事件全解析
前端·vue.js·面试