当前位置: 首页 > news >正文

【优先级队列(堆)】数据流的中位数(hard)

优先级队列(堆)

  • 数据流的中位数(hard)
    • 题⽬描述:
    • 解法(利⽤两个堆):
      • 算法思路:
    • 算法代码:

数据流的中位数(hard)

题⽬链接: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
提⽰:
-105 <= num <= 105
在调⽤ findMedian 之前,数据结构中⾄少有⼀个元素
最多 5 * 104次调⽤ addNum 和 findMedian

解法(利⽤两个堆):

在这里插入图片描述
在这里插入图片描述

算法思路:

这是⼀道关于「堆」这种数据结构的⼀个「经典应⽤」。
我们可以将整个数组「按照⼤⼩」平分成两部分(如果不能平分,那就让较⼩部分的元素多⼀个),较⼩的部分称为左侧部分,较⼤的部分称为右侧部分:
• 将左侧部分放⼊「⼤根堆」中,然后将右侧元素放⼊「⼩根堆」中;
• 这样就能在 O(1) 的时间内拿到中间的⼀个数或者两个数,进⽽求的平均数。
如下图所⽰:
在这里插入图片描述
于是问题就变成了「如何将⼀个⼀个从数据流中过来的数据,动态调整到⼤根堆或者⼩根堆中,并且保证两个堆的元素⼀致,或者左侧堆的元素⽐右侧堆的元素多⼀个」
为了⽅便叙述,将左侧的「⼤根堆」记为 left ,右侧的「⼩根堆」记为 right ,数据流中来的「数据」记为 x 。
其实,就是⼀个「分类讨论」的过程:

  1. 如果左右堆的「数量相同」, left.size() == right.size() :
    a. 如果两个堆都是空的,直接将数据 x 放⼊到 left 中;
    b. 如果两个堆⾮空:
    i. 如果元素要放⼊左侧,也就是 x <= left.top() :那就直接放,因为不会影响我们制定的规则;
    ii. 如果要放⼊右侧
    • 可以先将 x 放⼊ right 中,
    • 然后把 right 的堆顶元素放⼊ left 中 ;
  2. 如果左右堆的数量「不相同」,那就是 left.size() > right.size() :
    a. 这个时候我们关⼼的是 x 是否会放⼊ left 中,导致 left 变得过多:
    i. 如果 x 放⼊ right 中,也就是 x >= right.top() ,直接放;
    ii. 反之,就是需要放⼊ left 中:
    • 可以先将 x 放⼊ left 中,
    • 然后把 left 的堆顶元素放⼊ right 中 ;
    只要每⼀个新来的元素按照「上述规则」执⾏,就能保证 left 中放着整个数组排序后的「左半部分」, right 中放着整个数组排序后的「右半部分」,就能在 O(1) 的时间内求出平均数。

算法代码:

class MedianFinder
{PriorityQueue<Integer> left;PriorityQueue<Integer> right;public MedianFinder() {left = new PriorityQueue<Integer>((a, b) -> b - a); // ⼤根堆right = new PriorityQueue<Integer>((a, b) -> a - b); // ⼩根堆}public void addNum(int num) {// 分情况讨论if(left.size() == right.size()){if(left.isEmpty() || num <= left.peek()){left.offer(num);}else{right.offer(num);left.offer(right.poll());}}else{if(num <= left.peek()){left.offer(num);right.offer(left.poll());}else{right.offer(num);}}}public double findMedian() {if(left.size() == right.size()) return (left.peek() + right.peek()) / 2.0;else return left.peek();}
}
http://www.dtcms.com/a/537443.html

相关文章:

  • 【openGauss】从“functions in index expression must be marked IMMUTABLE“谈起
  • 拼团购物网站怎么做学网站开发
  • 【CMake】使用 CMake 构建 C/C++ 项目的标准流程详解
  • 最短路径——BFS
  • git“约定式提交” (Conventional Commits) 的规范
  • 上海做家教网站有哪些wordpress导航菜单制作
  • 【FPGA】时序逻辑计数器设计仿真验证
  • 【Camunda】工作流
  • 泸州市建设职工培训中心网站怎么建立本地网站
  • gunicorn和docker冲突吗
  • 学做网站多少钱青岛大型网站建设
  • 139.MIG DDR数据位宽选择72bit,带ecc时dm管脚会消失
  • 【Rust编程:从新手到大师】 Rust 数据类型全解析
  • C++十大排序算法
  • 公司网站维护由那个部门做百度竞价点击工具
  • Vue2 elementUI年份区间选择组件
  • 工装设计方案网站wordpress的仪表盘进不去
  • 深度学习笔记40-CGAN|生成手势图像
  • 浙江建设职业技术学院oa网站怎么做微信推广和宣传
  • React 08
  • 企业信息门户网站建设方案设计素材的网站
  • 如何将自己做的网站变成中文帮忙制作网页的公司
  • gpu driven:vello新执行流程
  • LangGraph的Agent长短时记忆的原理有什么区别,分别适用于什么业务场景
  • 定制网站开发的目的是什么做单位网站的公司吗
  • 做网站建立数据库自适应的网站模板
  • 路由硬盘做网站空间不中国城乡建中国城乡建设部网站
  • 电脑怎么做服务器 网站wordpress手机号网站
  • 跨境电商技术与运营双升级!亚马逊 / TikTok/Temu 本周新政解读,附卖家技术适配指南​
  • C++ 类的学习(七) 类的转换 和 嵌套类