1.题目要求

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

  • void addNum(int num) - 从数据流中添加一个整数到数据结构中。
  • double findMedian() - 返回目前所有元素的中位数。

示例:

  addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2

进阶:

    1. 如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
    2. 如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

2.解题思路

堆是一个非常重要的数据结构,堆排序在C++中的实现为优先级队列(Priority_queue),关于这一点,我的另一篇博文 "Leetcode 703. 数据流中的第K大元素"  有更详细提到,这里不做重复。

LeetCode网站把这一道划分在“堆”一类中,也是提醒我们使用堆结构。这道题很巧妙,我是听了算法课(牛客网的左程云大牛)的讲解才弄明白。这里的代码是自己听懂了思路,独立写出来的。

关键思路:建立两个堆(使用priority_queue实现),一个大根堆,一个小根堆。

(1)一个大根堆保存所有整数中较小的1/2;一个小根堆保存所有整数中较大的1/2
          (2)并且,依次添加元素过程中,两个堆元素个数的差的绝对值不能超过1

这样,两个堆建立好了以后,

(1)如果输入的元素个数 n 是偶数,则两个堆的元素个数相等,分别取大根堆的顶和小根堆的顶,取平均值,即是所求的整个数据流的中位数;

(2)如果输入的元素个数 n 是奇数,则必有一个堆的元素个数为(n/2+1),返回这个堆的顶,即为所求的中位数。

3.我的代码

个人比较喜欢写段落注释行注释,因为这样自己一年之后还能快速看懂,当然也方便他人,特别是一起刷题的伙伴,轻松看懂。

更多的细节讲解里都在注释里。如有错误的地方,欢迎多指正。

代码通过所有测试案例的时间为124ms。

class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() { } void addNum(int num) {
/*建立两个堆:(1)一个大根堆,保存所有整数中较小的1/2;一个小根堆,保存所有整数中较大的1/2;
(2)并且,依次添加元素过程中,两个堆大小的差的绝对值不能超过1; */ //第一元素加入大根堆
if(heap1.size()==){
heap1.push(num);
return;
} if(num<=heap1.top()){
//第二个元素比大根堆的顶小
heap1.push(num); //大根堆元素过多
if(heap1.size()-heap2.size()>)
{
int temp = heap1.top();
heap1.pop();
heap2.push(temp);//大根堆弹出顶到小根堆
} }
else{
//第二个元素比大根堆的顶大,直接进入小根堆
heap2.push(num); //小根堆元素过多
if(heap2.size()-heap1.size()>)
{
int temp = heap2.top();
heap2.pop();
heap1.push(temp);//小根堆弹出顶到大根堆
}
} } double findMedian() {
//输入的元素为奇数个
if(heap1.size() > heap2.size())
return heap1.top();
else if(heap1.size() < heap2.size())
return heap2.top(); //输入的元素个数为偶数
else
return (heap1.top()+heap2.top())/2.0;
//取大根堆、小根堆的堆顶元素取平均值,即为所求全局中位数
} private:
priority_queue<int> heap1;//默认,大根堆
priority_queue<int,vector<int>,greater<int>> heap2;//小根堆(升序序列) }; /**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/

4.用时更少的示例代码

这是我提交解答后,查看细节,看到的Leetcode官网上提交的关于这道题运行时间最短(96ms)的示例代码。

LeetCode上刷好多速度排名第一的代码中都有一段类似的代码,就是下面代码中的第一段代码——优化C++的IO速度。

/*一般地,C++的运行速度不如C的,主要原因是C++的输入输出流兼容了C的输入输出,因此,C++的速度才会变慢,
如果去掉C++的输入输出的兼容性的话,速度就和C的差不多了*/
static const auto __ = []() {
// turn off sync
std::ios::sync_with_stdio(false);
// untie in/out streams
std::cin.tie(nullptr);
return nullptr;
}(); class MedianFinder {
public:
/** initialize your data structure here. */ //使用vector实现两个堆,而不是priority_queue
vector<int> maxheap;
vector<int> minheap; bool flag = true; MedianFinder() {
} void addNum(int num) {
if(flag){
//构建小根堆
if(minheap.size()>&&num>minheap[]){
minheap.push_back(num);
push_heap(minheap.begin(),minheap.end(),greater<int>());
num = minheap[];
pop_heap(minheap.begin(),minheap.end(),greater<int>());
minheap.pop_back();
}
maxheap.push_back(num);
push_heap(maxheap.begin(),maxheap.end(),less<int>());
flag=false;
}else{
//构建大根堆
if(maxheap.size()>&&num<maxheap[]){
maxheap.push_back(num);
push_heap(maxheap.begin(),maxheap.end(),less<int>());
num = maxheap[];
pop_heap(maxheap.begin(),maxheap.end(),less<int>());
maxheap.pop_back();
}
minheap.push_back(num);
push_heap(minheap.begin(),minheap.end(),greater<int>());
flag=true;
}
} double findMedian() {
if(maxheap.size()<&&minheap.size()<)
return ;
if(flag){
return (maxheap[]+minheap[])/2.0;
}else{
return maxheap[];
}
}
}; /**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/

参考博客:

https://blog.csdn.net/xiaosshhaa/article/details/78136032   std::ios::sync_with_stdio(false); cin.tie(0);

Leetcode 295. 数据流的中位数的更多相关文章

  1. Java实现 LeetCode 295 数据流的中位数

    295. 数据流的中位数 中位数是有序列表中间的数.如果列表长度是偶数,中位数则是中间两个数的平均值. 例如, [2,3,4] 的中位数是 3 [2,3] 的中位数是 (2 + 3) / 2 = 2. ...

  2. [LeetCode] 295. Find Median from Data Stream 找出数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  3. LeetCode——295. Find Median from Data Stream

    一.题目链接: https://leetcode.com/problems/find-median-from-data-stream 二.题目大意: 给定一段数据流,要求求出数据流中的中位数,其中数据 ...

  4. 堆实战(动态数据流求top k大元素,动态数据流求中位数)

    动态数据集合中求top k大元素 第1大,第2大 ...第k大 k是这群体里最小的 所以要建立个小顶堆 只需要维护一个大小为k的小顶堆 即可 当来的元素(newCome)> 堆顶元素(small ...

  5. [LeetCode] 295. Find Median from Data Stream ☆☆☆☆☆(数据流中获取中位数)

    295. Find Median from Data Stream&数据流中的中位数 295. Find Median from Data Stream https://leetcode.co ...

  6. [leetcode]295. Find Median from Data Stream数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. [LeetCode] Find Median from Data Stream 找出数据流的中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  8. 295 Find Median from Data Stream 数据流的中位数

    中位数是排序后列表的中间值.如果列表的大小是偶数,则没有中间值,此时中位数是中间两个数的平均值.示例:[2,3,4] , 中位数是 3[2,3], 中位数是 (2 + 3) / 2 = 2.5设计一个 ...

  9. [Swift]LeetCode295. 数据流的中位数 | Find Median from Data Stream

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

随机推荐

  1. hive创建外部表

    Create [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data_type [COMMENT col_comment], ...)] ...

  2. 软件工程课堂作业(十一)——NABC分析

    一.团队开发项目:基于Android的重力感应的解锁APP 二.项目特点:区别于一般解锁软件用开机按钮开锁解锁,我们的重力解锁软件根据动作实现解锁,减少了开机按钮的使用频率,提高寿命. 三.NABC分 ...

  3. TCP系列10—连接管理—9、syncookie、fastopen与backlog

    这部分内容涉及较多linux实现,可以跳过. 一.listen系统调用对backlog的处理 当socket处于LISTEN或者CLOSED状态时,fastopen队列的长度可以通过TCP_FASTO ...

  4. 【week2】 词频统计第一次更新

    词频统计: 对每个功能预计时间: 功能 预计(min) 实际(min) 数据流读入 20 40 正则规范字符串 15 20 排序 30 45 输出 20 30 其他   25 词频统计psp 日期 类 ...

  5. java中sql语句能不能加分号的问题?

    一.原因  在程序运行中,当执行sql后总是报无效字符错误:但是把程序放在pl/sql中执行又没有错误.让我很纳闷!于是我开始查找资料,然后我终于发现了问题. 二.问题剖析 原来在程序中:如果你在程序 ...

  6. [剑指Offer] 52.正则表达式匹配

    题目描述 请实现一个函数用来匹配包括'.'和'*'的正则表达式.模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次). 在本题中,匹配是指字符串的所有字符匹配整个模式 ...

  7. 能选择日期范围js控件

    html页面中使用日期控件是常有的事,好控件能使用开发变的快捷,下面是在开发过程中发现的几款日期控件,比较不错,收藏 1.基于bootstrap的jQuery日期范围选择插件 2.jQuery多功能日 ...

  8. hdu2295-Radar

    有n个城市,\(m\)个雷达,\(k\)个操作员,每个操作员只能操作一个雷达.每个雷达的覆盖范围是一个以雷达坐标为中心的圆,所有雷达的覆盖半径是相同的. 现在给出这\(n\)个城市,\(m\)个雷达的 ...

  9. Python Collections详解

    Python Collections详解 collections模块在内置数据结构(list.tuple.dict.set)的基础上,提供了几个额外的数据结构:ChainMap.Counter.deq ...

  10. C# 利用FTP自动下载xml文件后利用 FileSystemWatcher 监控目录下文件变化并自动更新数据库

    using FtpLib; using System; using System.Collections.Generic; using System.ComponentModel; using Sys ...