本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目 

  如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

思路

  所谓数据流,就是不会一次性读入所有数据,只能一个一个读取,每一步都要求能计算中位数。

  将读入的数据分为两部分,一部分数字小,另一部分大。小的一部分采用大顶堆存放,大的一部分采用小顶堆存放。当总个数为偶数时,使两个堆的数目相同,则中位数=大顶堆的最大数字与小顶堆的最小数字的平均值;而总个数为奇数时,使小顶堆的个数比大顶堆多一,则中位数=小顶堆的最小数字。

  因此,插入的步骤如下:

  1.若已读取的个数为偶数(包括0)时,两个堆的数目已经相同,将新读取的数插入到小顶堆中,从而实现小顶堆的个数多一。但是,如果新读取的数字比大顶堆中最大的数字还小,就不能直接插入到小顶堆中了 ,此时必须将新数字插入到大顶堆中,而将大顶堆中的最大数字插入到小顶堆中,从而实现小顶堆的个数多一。

  2若已读取的个数为奇数时,小顶堆的个数多一,所以要将新读取数字插入到大顶堆中,此时方法与上面类似。

测试算例 

  1.功能测试(读入奇/偶数个数字)

  2.边界值测试(读入0个、1个、2个数字)

Java代码

//题目:如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么
//中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,
//那么中位数就是所有数值排序之后中间两个数的平均值。 import java.util.PriorityQueue;
import java.util.Comparator; public class StreamMedian {
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(); //小顶堆,默认容量为11
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆,容量11
public int compare(Integer i1,Integer i2){
return i2-i1;
}
});
public void Insert(Integer num) {
if(((minHeap.size()+maxHeap.size())&1)==0){//偶数时,下个数字加入小顶堆
if(!maxHeap.isEmpty() && maxHeap.peek()>num){
maxHeap.offer(num);
num=maxHeap.poll();
}
minHeap.offer(num);
}else{//奇数时,下一个数字放入大顶堆
if(!minHeap.isEmpty() && minHeap.peek()<num){
minHeap.offer(num);
num=minHeap.poll();
}
maxHeap.offer(num);
}
} public Double GetMedian() {
if((minHeap.size()+maxHeap.size())==0)
throw new RuntimeException();
double median;
if((minHeap.size()+maxHeap.size()&1)==0){
median=(maxHeap.peek()+minHeap.peek())/2.0;
}else{
median=minHeap.peek();
}
return median;
}
}

  

收获

  1.最大最小堆可以用PriorityQueue实现,PriorityQueue默认是一个小顶堆,通过传入自定义的Comparator函数可以实现大顶堆:

    PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(11,new Comparator<Integer>(){ //大顶堆,容量11
@Override
public int compare(Integer i1,Integer i2){
return i2-i1; //降序排列
}
});

  PriorityQueue的常用方法有:poll(),offer(Object),size(),peek()等。

  2.平均值应该定义为double,且(a+b)/2.0 。

  3.往最大堆中插入数据时间复杂度是O(logn),获取最大数的时间复杂度是O(1)。

  4.这道题关键在于分成两个平均分配的部分,奇偶时分别插入到最大最小堆中,利用最大最小堆性质的插入方法要掌握。

更多:《剑指Offer》Java实现合集  

  

【Java】 剑指offer(41) 数据流中的中位数的更多相关文章

  1. 剑指 Offer 41. 数据流中的中位数 + 堆 + 优先队列

    剑指 Offer 41. 数据流中的中位数 Offer_41 题目详情 题解分析 本题使用大根堆和小根堆来解决这个寻找中位数和插入中位数的问题. 其实本题最直接的方法是先对数组进行排序,然后取中位数. ...

  2. 每日一题 - 剑指 Offer 41. 数据流中的中位数

    题目信息 时间: 2019-06-30 题目链接:Leetcode tag: 大根堆 小根堆 难易程度:中等 题目描述: 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有 ...

  3. [剑指offer] 41. 数据流中的中位数 (大小堆,优先队列)

    对于海量数据与数据流,用最大堆,最小堆来管理. class Solution { public: /* * 1.定义一个规则:保证左边(大顶堆)和右边(小顶堆)个数相差不大于1,且大顶堆的数值都小于等 ...

  4. 【剑指Offer】数据流中的中位数 解题报告(Python)

    [剑指Offer]数据流中的中位数 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews ...

  5. Go语言实现:【剑指offer】数据流中的中位数

    该题目来源于牛客网<剑指offer>专题. 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位 ...

  6. 剑指offer:数据流中的中位数(小顶堆+大顶堆)

    1. 题目描述 /** 如何得到一个数据流中的中位数? 如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值. 如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两 ...

  7. 剑指Offer 63. 数据流中的中位数(其他)

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.我们 ...

  8. 《剑指offer》-数据流中的中位数

    如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. 最开始的思路 ...

  9. [剑指Offer] 63.数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. c ...

随机推荐

  1. Elastic Job入门(3) - 集成Springboot

    引入pom文件 <dependency> <groupId>com.dangdang</groupId> <artifactId>elastic-job ...

  2. 第16月第6天 vs2005 lseek directdraw

    1. //_lseek(file_handle, -(int)pbitmap->bitmapinfoheader.biSizeImage, SEEK_END); SetFilePointer(( ...

  3. Database学习 - mysql数据类型约束

    mysql数据类型 - 属性

  4. 2018-2019-2 《网络对抗技术》Exp0 Kali安装 20165230

    2018-2019-2 <网络对抗技术>Exp0 Kali安装 20165230 一.下载kali 下载地址 下载Kali Linux 64 bit VMware VM版本 下载vmwar ...

  5. np.savetxt()——将array保存到txt文件,并保持原格式

    问题:1.如何将array保存到txt文件中?2.如何将存到txt文件中的数据读出为ndarray类型? 需求:科学计算中,往往需要将运算结果(array类型)保存到本地,以便进行后续的数据分析. 解 ...

  6. 嵌入式linux系统中,lsusb出现unable to initialize libusb: -99 解决办法 【转】

    转自:http://cpbest.blog.163.com/blog/static/41241519201111575726966/ libusb是linux系统中,提供给用户空间访问usb设备的AP ...

  7. 四种加载React数据的技术对比(Meteor 转)

    1.四种加载React数据的技术对比(Meteor 转) : https://sanwen8.cn/p/31e4kdE.html 2. Meteor + Appolo   TelescopeJS/Te ...

  8. Shell脚本中执行sql语句操作mysql的5种方法【转】

    对于自动化运维,诸如备份恢复之类的,DBA经常需要将SQL语句封装到shell脚本.本文描述了在Linux环境下mysql数据库中,shell脚本下调用sql语句的几种方法,供大家参考.对于脚本输出的 ...

  9. JS实现双击内容变为可编辑状态

    在一些网站上我们经常看到交互性很强的功能.一些用户资料可以直接双击出现文本框,并在此输入新的资料即可修改,无需再按确定按钮等.. 我在网上查了很多资料,但都有一个小bug,就是当获取焦点后,光标的位置 ...

  10. git强制覆盖更新

    1.选择项目,右键选择Team,选择Team里面的Reset. 2.点击Reset后弹出Reset窗口,选择Hard选项,这样就会把远端的项目完全拉下来覆盖本地,本地没有的文件也会被创建,点击确定.