数据流的中位数

优质博文IT-BLOG-CN

一、题目

中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
【1】 例如arr = [2,3,4]的中位数是3
【2】例如arr = [2,3]的中位数是(2 + 3) / 2 = 2.5

实现MedianFinder类:
【1】MedianFinder()初始化MedianFinder对象。
【2】void addNum(int num)将数据流中的整数num添加到数据结构中。
【3】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次调用addNumfindMedian

二、代码

优先队列

在这里插入图片描述

我们用两个优先队列queMaxqueMin分别记录大于中位数的数和小于等于中位数的数。当累计添加的数的数量为奇数时,queMin中的数的数量比queMax多一个,此时中位数为queMin的队头。当累计添加的数的数量为偶数时,两个优先队列中的数的数量相同,此时中位数为它们的队头的平均值。

当我们尝试添加一个数num到数据结构中,我们需要分情况讨论:
【1】num≤max⁡{queMin}此时num小于等于中位数,我们需要将该数添加到queMin中。新的中位数将小于等于原来的中位数,因此我们可能需要将queMin中最大的数移动到queMax中。
【2】num>max⁡{queMin}此时num大于中位数,我们需要将该数添加到queMin中。新的中位数将大于等于原来的中位数,因此我们可能需要将queMax中最小的数移动到queMin中。

特别地,当累计添加的数的数量为0时,我们将num添加到queMin中。

class MedianFinder {PriorityQueue<Integer> queMin;PriorityQueue<Integer> queMax;public MedianFinder() {queMin = new PriorityQueue<Integer>((a, b) -> (b - a));queMax = new PriorityQueue<Integer>((a, b) -> (a - b));}public void addNum(int num) {if (queMin.isEmpty() || num <= queMin.peek()) {queMin.offer(num);if (queMax.size() + 1 < queMin.size()) {queMax.offer(queMin.poll());}} else {queMax.offer(num);if (queMax.size() > queMin.size()) {queMin.offer(queMax.poll());}}}public double findMedian() {if (queMin.size() > queMax.size()) {return queMin.peek();}return (queMin.peek() + queMax.peek()) / 2.0;}
}

时间复杂度: addNum: O(logn),其中n为累计添加的数的数量。findMedian: O(1)
空间复杂度: O(n),主要为优先队列的开销。

有序集合 + 双指针

我们也可以使用有序集合维护这些数。我们把有序集合看作自动排序的数组,使用双指针指向有序集合中的中位数元素即可。当累计添加的数的数量为奇数时,双指针指向同一个元素。当累计添加的数的数量为偶数时,双指针分别指向构成中位数的两个数。

当我们尝试添加一个数num到数据结构中,我们需要分情况讨论:
【1】初始有序集合为空时,我们直接让左右指针指向num所在的位置。
【2】有序集合为中元素为奇数时,leftright同时指向中位数。如果num大于等于中位数,那么只要让left左移,否则让right右移即可。

有序集合为中元素为偶数时,leftright分别指向构成中位数的两个数。
【1】当num成为新的唯一的中位数,那么我们让left右移,right左移,这样它们即可指向num所在的位置;
【2】当num大于等于right,那么我们让left右移即可;
【3】当num小于right指向的值,那么我们让right左移,注意到如果num恰等于left指向的值,那么num将被插入到left右侧,使得leftright间距增大,所以我们还需要额外让left指向移动后的right

class MedianFinder {TreeMap<Integer, Integer> nums;int n;int[] left;int[] right;public MedianFinder() {nums = new TreeMap<Integer, Integer>();n = 0;left = new int[2];right = new int[2];}public void addNum(int num) {nums.put(num, nums.getOrDefault(num, 0) + 1);if (n == 0) {left[0] = right[0] = num;left[1] = right[1] = 1;} else if ((n & 1) != 0) {if (num < left[0]) {decrease(left);} else {increase(right);}} else {if (num > left[0] && num < right[0]) {increase(left);decrease(right);} else if (num >= right[0]) {increase(left);} else {decrease(right);System.arraycopy(right, 0, left, 0, 2);}}n++;}public double findMedian() {return (left[0] + right[0]) / 2.0;}private void increase(int[] iterator) {iterator[1]++;if (iterator[1] > nums.get(iterator[0])) {iterator[0] = nums.ceilingKey(iterator[0] + 1);iterator[1] = 1;}}private void decrease(int[] iterator) {iterator[1]--;if (iterator[1] == 0) {iterator[0] = nums.floorKey(iterator[0] - 1);iterator[1] = nums.get(iterator[0]);}}
}

时间复杂度: addNum: O(logn),其中n为累计添加的数的数量。findMedian: O(1)
空间复杂度: O(n),主要为有序集合的开销。

进阶 1 如果数据流中所有整数都在0100范围内,那么我们可以利用计数排序统计每一类数的数量,并使用双指针维护中位数。
进阶 2 如果数据流中99%的整数都在0100范围内,那么我们依然利用计数排序统计每一类数的数量,并使用双指针维护中位数。对于超出范围的数,我们可以单独进行处理,建立两个数组,分别记录小于0的部分的数的数量和大于100的部分的数的数量即可。当小部分时间,中位数不落在区间[0,100]中时,我们在对应的数组中暴力检查即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/745430.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

​LLM之新手入门:大预言模型的概念介绍与应用

最近&#xff0c;我在系统地学习大型语言模型&#xff08;LLM&#xff09;的相关知识。在这个学习过程中&#xff0c;我努力将所学的内容整理成博客文章。在这篇博客中&#xff0c;我首先简要介绍了人工智能的发展历史&#xff0c;然后探讨了大型模型的基本原理、训练方法、微调…

Linux系列

安装系列 1.MySQL安装 我们要通过rpm&#xff0c;进行MySQL数据库的安装&#xff0c;主要的步骤如下&#xff1a; rpm -qa 查询当前系统中安装的所有软件 rpm -qa | grep mysql 查询当前系统中安装的名称带mysql的软件 rpm -…

uniapp微信小程序_拍照从相册选择

userImg() {let that thisuni.chooseMedia({count: 1,mediaType: [image, video],sourceType: [album, camera],maxDuration: 30,camera: back,success(res) {console.log(res.tempFiles[0].tempFilePath)that.imagUrl res.tempFiles[0].tempFilePath}})}, 直接调用api即可,注…

sqllab第十二关通关笔记

知识点&#xff1a; 一般字符型注入分类 单引号闭合双引号闭合这是一个双引号闭合 看界面又是一个输入框的注入;通过admin admin进行登录发现页面还是有回显 直接使用万能密码尝试 构造payload:usernameadminor11 没有任何反应&#xff1b;可能是没加注释符的关闭 构造user…

基于JAVA的教务系统小程序的设计与实现【附项目源码】分享

基于JAVA的教务系统小程序的设计与实现: 源码地址&#xff1a;https://download.csdn.net/download/qq_41810183/88842782 一、引言 随着信息技术的不断发展&#xff0c;教务管理工作逐渐走向数字化、智能化。为了提高教务管理效率&#xff0c;方便师生查询教务信息&#xff…

OpenAI的GPT-4.5 Turbo:意外曝光且可能在六月份推出

网络媒体THE DECODER的联合创始人兼出版人Matthias认为&#xff0c;人工智能技术将彻底改变人类和计算机的互动方式。 最新消息显示&#xff0c;OpenAI的最新力作GPT-4.5 Turbo已经在网络上意外曝光。首批发现此信息的是Bing和DuckDuck Go等搜索引擎&#xff0c;它们在官方发布…

8-图像放大

其实&#xff0c;就是开辟一个zoomwidth&#xff0c;zoomheight的内存&#xff0c;再分别赋值即可。 void CDib::Maginify(float xZoom, float yZoom) { //指向原图像指针 LPBYTE p_data GetData(); //指向原像素的指针 LPBYTE lpSrc; //指向缩放图像对应像素的指针 LPBYTE l…

【STM32中断EXTI详细介绍与总结】

STM32中断EXTI 中断的介绍中断简介中断优先级中断嵌套 STM32中断NVIC介绍作用功能如何分组 EXTI简介EXTI结构EXTI框图 AFIO介绍主要功能和作用&#xff1a; 中断配置步骤 一个中断时的代码初始化两个中断时的代码和错误提示 中断的介绍 中断简介 中断&#xff1a;在主程序运行…

亚信安慧AntDB在数据可靠性和系统安全中的实践

亚信安慧AntDB以持续创新和技术进步为理念&#xff0c;不断优化性能和功能&#xff0c;至今已经保持了15年的平稳运行。这一漫长的历程并非偶然&#xff0c;而是源于AntDB团队对技术的不懈探索和追求。他们始终秉承着“永不停歇&#xff0c;永不满足”的信念&#xff0c;将技术…

Jmeter扩展开发--自定义java取样器

简介 jmeter内置了包括&#xff1a;http、https、tcp等各种协议的支持&#xff0c;通常情况只需要做简单的参数配置即可使用。但在某些特殊情况下&#xff0c;还是希望能做自定义压测处理&#xff0c;此时就涉及Jmeter的扩展开发自定义Java取样器&#xff0c;如下图所示&#…

基于centos7的k8s最新版v1.29.2安装教程

k8s概述 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态&#xff0c;其服务、支持和工具的使用范围相当广泛。 Kubernetes 这个名字源于希腊语&…

Github主页设置贪吃蛇详细教程

先看最终实现结果&#xff1a; 有条贪吃蛇放在主页还是蛮酷的哈哈哈。接下来我来讲一讲怎么在Github主页添加一条贪吃蛇。 首先要修改自己的Github的主页&#xff0c;我们得有一个特殊的仓库——这个仓库必须与你的Github用户名保持一致&#xff0c;并且需要公开&#xff0c…

力扣日记3.14-【贪心算法篇】376. 摆动序列

力扣日记&#xff1a;【贪心算法篇】376. 摆动序列 日期&#xff1a;2024.3.14 参考&#xff1a;代码随想录、力扣 376. 摆动序列 题目描述 难度&#xff1a;中等 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称为 摆动序列 。第一个差&#xff08;…

python毕业设计基于flask应急救援调度系统django

此系统设计主要采用的是python语言来进行开发&#xff0c;采用flask框架技术&#xff0c;框架分为三层&#xff0c;分别是控制层Controller&#xff0c;业务处理层Service&#xff0c;持久层dao&#xff0c;能够采用多层次管理开发&#xff0c;对于各个模块设计制作有一定的安全…

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024)

【投稿优惠-EI稳定检索】2024年图像处理与机械系统工程国际学术会议 (ICIPMSE 2024) 大会主题: (主题包括但不限于, 更多主题请咨询会务组苏老师) 图像处理 基于图像的渲染 计算机视觉 可视化分析 模式识别 3D打印 渲染和动画 渲染技术 电脑动画 基于草图的建模 机械…

苹果Find My App用处多多,产品认准伦茨科技ST17H6x芯片

苹果发布AirTag发布以来&#xff0c;大家都更加注重物品的防丢&#xff0c;苹果的 Find My 就可以查找 iPhone、Mac、AirPods、Apple Watch&#xff0c;如今的Find My已经不单单可以查找苹果的设备&#xff0c;随着第三方设备的加入&#xff0c;将丰富Find My Network的版图。产…

Unity Timeline学习笔记(2) - PlayableTrack

PlayableTrack 是可自定义播放的轨道。我们可以通过进入轨道后调用自己的函数方法&#xff0c;使用起来也是比较顺手的。 添加轨道 我们点击加号添加 这样就有一个空轨道了&#xff0c;然后我们创建两个测试脚本。 添加脚本 分别是Playable Behaviour和PlayableAsset脚本。…

unity报错出现Asset database transaction committed twice!

错误描述&#xff1a; 运行时报错 Assertion failed on expression: ‘m_ErrorCode MDB_MAP_RESIZED || !HasAbortingErrors()’Asset database transaction committed twice!Assertion failed on expression: ‘errors MDB_SUCCESS || errors MDB_NOTFOUND’ 解决办法&…

MySQL:概念简章

1.SQL通用语法 SQL单行、多行书写&#xff0c;以分号结尾SQL可以以空格有缩进增加代码可读性SQL语句不区分大小写 2.SQL语句分类 2.1 DDL&#xff08;数据定义语言&#xff09; 用于数据库、数据表、字段的定义的语言 create by 表名 &#xff08;表里有什么字段&#xff09;…

幼儿园管理系统|基于springboot框架+ Mysql+Java+Tomcat的幼儿园管理系统设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 用户功能模块 管理员功能登录前台功能效果图 教师功能模块 系统功能设计 数据库E-R图设计 lunwen参…