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

295.数据流的中位数

        先来看中位数的定义,提取一下关键词,中位数将一组按照顺序排序好的数据,分成两部分,例如 1 2 3 4 5 6,中位数 3.5 将数据分成了[1,2,3]和[4,5,6],想看定义的同学可以自行阅读

        中位数(Median)又称中值,统计学中的专有名词,是按顺序排列的一组数据中居于中间位置的数,代表一个样本、种群或概率分布中的一个数值,其可将数值集合划分为相等的上下两部分。对于有限的数集,可以通过把所有观察值高低排序后找出正中间的一个作为中位数。如果观察值有偶数个,通常取最中间的两个数值的平均数作为中位数。

        解法一:暴力解法

        核心思路是直接按顺序插入新元素。计算中位数时分为两种情况:当数组长度为奇数时直接返回中间元素;当长度为偶数时则取中间两个元素的平均值。该算法的时间复杂度为O(n),每个元素的插入操作耗时O(logn)。虽然效率不高,但对于题目给定的5*10^4*10^5级别数据量仍可勉强通过。

class MedianFinder {
public:vector<double> arr;MedianFinder() {}void addNum(int num) {auto it = ranges::lower_bound(arr.begin(),arr.end(),num);arr.insert(it,num);}double findMedian() {int n = arr.size();if (n % 2 == 1) {return arr[n / 2];}else{return (arr[(n - 1) / 2] + arr[n / 2]) / 2.0;}}
};

        时间复杂度:O(n)

        空间复杂度:O(1)

       解法二:利用数据中位数将数据分成两部分的特性,我们可以采用最小堆 right 和最大堆 left 来实现。例如对于数组[1,2,3,4,5,6],left 存储[1,2,3],right 存储[4,5,6],中位数即为 left 堆顶3和right 堆顶4的平均值。

在addNum操作不断插入新数据时,为了保证能快速通过堆顶元素计算中位数,需要始终遵循以下原则:

  1. left中的所有元素均小于right中的元素
  2. left的长度等于right的长度,或比right多1

具体维护方法如下:

  • 当前left的长度等于right的长度

            插入的元素较大:新元素放入 right 中,此时 right 的长度比 left 大,需要将 right 的最小值(堆顶)放入 left ,然后 right 弹出堆顶

            插入的元素较小:新元素放入 left 中,此时 left 的长度比 right 多1,符合原则

            以上两种情况可以归结于,right 放入新元素,将 right 的堆顶放入 left ,right 弹出堆顶

  • 当前 left 的长度比 right 多1

            插入的元素较大:新元素放入 right 中,此时 left 长度与 right 长度相等,符合原则

            插入的元素较小:新元素放入 left 中,此时 left 长度比 right 多 2,需要将 left 的最大值(堆顶)放入 right,left 弹出堆顶

            以上两种情况可以归结于,left 放入新元素,将 left 的堆顶放入 right ,left 弹出堆顶

最终,若 left 长度大于 right,则中位数为left堆顶;否则中位数为两个堆顶的平均值。

        代码:

class MedianFinder {
public:priority_queue<int> left;priority_queue<int,vector<int>,greater<>> right; MedianFinder() {}void addNum(int num) {if (left.size() == right.size()) {right.emplace(num);left.emplace(right.top());right.pop();}else{left.emplace(num);right.emplace(left.top());left.pop();}}double findMedian() {if (left.size() > right.size()) {return left.top();}else{return (left.top() + right.top()) / 2.0;}}
};/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder* obj = new MedianFinder();* obj->addNum(num);* double param_2 = obj->findMedian();*/

        时间复杂度:O(logn)

        空间复杂度:O(1)

http://www.xdnf.cn/news/9195.html

相关文章:

  • 摩尔线程 MUSA 软件开发集成套件
  • 使用 qiankun 实现 Vue3 与 Avalon 混合应用集成实践
  • 一些git的常见操作记录
  • C50-指针数组
  • [灵龙AI API] AI生成视频API:文生视频 – 第2篇
  • 嵌入式开发新范式:NTP时间同步实验与高精度仿真平台实践
  • OpenGAN:基于开放数据生成的开放集识别
  • 一周学会Pandas2之Python数据处理与分析-Pandas2数据合并与对比-df.combine():元素级合并
  • 统一人体姿态估计与分割的新方法:KDC
  • C# Windows Forms应用程序-003
  • day 37
  • IP协议解析
  • 使用json传递信息时接收不到的问题
  • python做题日记(9)
  • 【AI News | 20250526】每日AI进展
  • AI时代新词-私有数据与AI结合的技术:隐私保护与数据利用的平衡
  • pg库分表操作步骤- PostgreSQL 分区表
  • 车载通信网络 --- 传统车载网络及其发展
  • 固态硬盘的寿命与可靠性如何保障?——以Kingston FURY Renegade G5为例的专业解析
  • 自动编码器 潜在空间 Autoencoders 视频截图
  • 浏览器指纹科普 | 语言 vs 界面语言,区别是什么?
  • GitLab-CI快速开始
  • gin使用Mysql连接池用法
  • IDEA没有出现TODO
  • 实在Agent成业界首批全面适配鸿蒙、麒麟、统信信创系统的智能体
  • git clone 提速
  • redis在Spring中的一些使用
  • 用llama3微调了一个WiFiGPT 用于室内定位
  • Linux文本搜索——grep命令详解
  • PostGIS实现二进制转栅格数据应用实践【ST_RastFromWKB】