算法通过村第十四关-堆|黄金笔记|中位数

文章目录


前言


提示:我独自度过了太多的时光,沉默已成一种习惯。 帕瑞尔·马卡姆《夜航西飞》

这个是一个比较难的题目,要不尝试一下看看。

数据流中的中位数的问题

参考题目地址:295. 数据流的中位数 - 力扣(LeetCode)


进阶问题:

  1. 如果数据流中所有整数都在0到100范围内呢,你将如何优化你的算法?
  2. 如果数据流中99%的整数都在0到100范围内呢?你将如何优化你的算法?

我们分析一下:

这道题说真的挺难的,如果没有专门的学过,很难再面试中想到。

中位数的题目,我们一般可以采用 大顶堆 + 小顶堆 来求解,下面我们通过直观的例子了解下怎么处理:

小顶堆:存储所有元素中较大的一半,堆顶存储的其实是最小的数。

大顶堆:存储所有元素中较小的一半,堆顶存储的其实是最大的数。

相当于,把所有元素分成大小两半,而我们计算中位数,只需要大的那半的最小值和小的那半的最大值就可以了。

比如:我们依次添加【1,2,3,4,5】,砍成两半为【1,2】和【3,4,5】。我们是需要快速找到 2 和 3 就可以了。

下面我们看看两个堆是怎么变化的:

  1. 添加1,进入minHeap中,中位数为1
  2. 添加2 ,它比minHeap堆顶的元素大1,进入minHeap,minHeap中的元素超过所有元素总和的一半,所以要平衡一下,分给maxHeap,中位数为(1 + 2 )/ 2 = 1.5;
  3. 添加 3 ,它比minHeap堆顶元素2 大,进入minHeap,中位数为2;
  4. 添加4 ,它比minHeap堆顶的元素2大,进入minHeap,minHeap中的元素超过所有元素总和的一半,所以要平衡一下,分给maxHeap,中位数为(2+ 3 )/ 2 = 2.5;
  5. 添加 5,它比minHeap堆顶元素3 大,进入minHeap,中位数为3;

Java中堆(即使优先队列)是使用完全二叉树实现的。理解以下,我们看代码怎么做,代码写起来比较简单,但是实现起来还挺麻烦的。

java 复制代码
class MedianFinder {
    // 这里小顶堆 存储较大的一半(最小值在堆顶
    PriorityQueue<Integer> minHeap;
    // 这里大顶堆 存储较小的一半(最大值在堆顶
    PriorityQueue<Integer> maxHeap;
    public MedianFinder() {
        minHeap = new PriorityQueue<>();
        maxHeap = new PriorityQueue<>((a,b) -> b - a);
    }
    
    public void addNum(int num) {
        // 小顶堆存储大的元素,num只要大于元素中最小的,就入堆
        if(minHeap.isEmpty() || num > minHeap.peek()){
            minHeap.offer(num);
            if(minHeap.size() - maxHeap.size() > 1){
                maxHeap.offer(minHeap.poll());
            }
        }else{
            maxHeap.offer(num);
            // 可以确保多的那个元素一定在minHeap
            if(maxHeap.size() - minHeap.size() > 0){
                minHeap.offer(maxHeap.poll());
            }
        }
    }
    
    public double findMedian() {
        if(minHeap.size() > maxHeap.size()){
            return minHeap.peek();
        }else if(minHeap.size() < maxHeap.size()){
            return maxHeap.peek();
        }else{
            return (minHeap.peek() + maxHeap.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();
 */

总结

提示:堆的经典应用;大顶堆小顶堆;中位数问题;特殊解法;优先队列(priority):


如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ ("▔□▔)/ 如有不理解的地方,欢迎你在评论区给我留言,我都会逐一回复 ~ 也欢迎你 关注我 ,喜欢交朋友,喜欢一起探讨问题。

相关推荐
云-缩影几秒前
拆解 AI 图像生成应用的后端架构:ECS、OSS 和大模型 API 怎么配合
java·spring boot·后端
瑞克-桑切斯22 分钟前
7、MySQL 慢查询排查与优化实战指南
java·服务器·数据库
海的透彻5 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
code2cat5 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习6 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one6 小时前
算法--构造
java·数据结构·算法
SL_staff6 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff7 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
Mikko77 小时前
Redis 连接数满了服务端有错误信息吗?连接数不增加却命令超时?6.2 实测连接池、超时与大 key 怎么判定
java·spring boot·redis·后端
.Bryce.7 小时前
从零到一开发技术名词大全:从需求分析到 AI Agent 工程
java·网络·人工智能·agent·需求分析·agent评测