数据流的中位数

优质博文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,一经查实,立即删除!

相关文章

GPT如何做角色扮演,prompt示例大放送

文末有完整版角色扮演提示词。 角色扮演在AI提示词中有着至关重要的作用。 无论结构化指令,还是文本格式指令,角色扮演都是很实用也是比较容易上手的提示词的重要组成部分。 我们可以通过让ChatGPT扮演特定的角色,来获得更加贴合需求的、具有特定视角和专业知识背景的答案…

​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即可,注…

华为认证云计算专家(HCIE-Cloud Computing)–多选题

华为认证云计算专家&#xff08;HCIE-Cloud Computing&#xff09;–多选题 3.( 多选题 ) 某企业有一个购物系统部署在HCS&#xff0c;可以选择哪些服务做安全保障? A WAF B HSS C DBAS D BHD 正确答案&#xff1a;ABCD 5.(多选题) 主机安全服务HSS的功能包括哪些? A 资产管…

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;它们在官方发布…

知识点总结,c,c++的各种知识点

、1、C/C 1.1 关键字 &#xff08;参考”嵌入式及Linux那些事“以及众多帖子汇总而成&#xff09; volatile ​ 当声明指向设备寄存器的指针时一定要用volatile&#xff0c;它会告诉编译器不要对存储在这个地 址的数据进行假设。 ​ 中断服务程序中修改的供其他程序检测的变…

8-图像放大

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

Visual Studio ERROR : LNK2001 和LNK2019

Visual Studio ERROR : LNK2001 和LNK2019 LNK2001解决方案 LNK2019解决方案 LNK2001 是由于参与编译的一些文件里面使用的函数&#xff0c;这些函数的实现所在的文件未参与编译。 解决方案 将这些函数的实现文件也参与编译即可。 LNK2019 在函数中使用的另一个函数无法识…

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

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

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

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

【dp】砝码称重模型(选或不选)

目录 蓝桥杯 砝码称重 牛客 我不是大富翁 abc 344 D cf div3 933 D 蓝桥杯 砝码称重 题目链接&#xff1a; https://www.lanqiao.cn/problems/1447/learning/?page1&first_category_id1&sortstudents_count&category_id3&name%E7%A0%9D%E7%A0%81%E7%A7%…

Ubuntu20.04配置C/C++环境

1. C/C++ IDE 安装Clion Nova和VsCode 2. 编译器 2.1 g++ 当程序比较小时,安装g++编译器进行编译,常用命令如下: // 安装g++ sudo apt-get install g++ // 默认生成a.out的可执行文件 g++ main.cpp // 生成其他名字的可执行文件 g++ main.cpp -o exe_name2.2 cmake 当…

【leetcode题解C++】146. LRU缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#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 这个名字源于希腊语&…

分布式微服务 - 4.服务增强 - 1.概念

分布式微服务 - 4.服务增强 - 1.概念 项目示例&#xff1a; 无 内容提要&#xff1a; 配置中心、框架 文档&#xff1a; 无 配置中心 随着需求的不断开发实现&#xff0c;系统逐渐庞大&#xff0c;微服务逐渐增多&#xff0c;系统涉及到的配置信息不断增多&#xff0c;…

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

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