Leetcode 295. 数据流的中位数
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
进阶:
- 如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
- 如果数据流中 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. 数据流的中位数的更多相关文章
- Java实现 LeetCode 295 数据流的中位数
295. 数据流的中位数 中位数是有序列表中间的数.如果列表长度是偶数,中位数则是中间两个数的平均值. 例如, [2,3,4] 的中位数是 3 [2,3] 的中位数是 (2 + 3) / 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 ...
- LeetCode——295. Find Median from Data Stream
一.题目链接: https://leetcode.com/problems/find-median-from-data-stream 二.题目大意: 给定一段数据流,要求求出数据流中的中位数,其中数据 ...
- 堆实战(动态数据流求top k大元素,动态数据流求中位数)
动态数据集合中求top k大元素 第1大,第2大 ...第k大 k是这群体里最小的 所以要建立个小顶堆 只需要维护一个大小为k的小顶堆 即可 当来的元素(newCome)> 堆顶元素(small ...
- [LeetCode] 295. Find Median from Data Stream ☆☆☆☆☆(数据流中获取中位数)
295. Find Median from Data Stream&数据流中的中位数 295. Find Median from Data Stream https://leetcode.co ...
- [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 ...
- [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 ...
- 295 Find Median from Data Stream 数据流的中位数
中位数是排序后列表的中间值.如果列表的大小是偶数,则没有中间值,此时中位数是中间两个数的平均值.示例:[2,3,4] , 中位数是 3[2,3], 中位数是 (2 + 3) / 2 = 2.5设计一个 ...
- [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 ...
随机推荐
- 爬虫2.2-scrapy框架-文件写入
目录 scrapy框架-文件写入 1. lowb写法 2. 高端一点的写法 3. 优化版本 scrapy框架-文件写入 1. lowb写法 ~pipelines.py 前提回顾,spider.py中 ...
- Android开发-API指南-<permission>
<permission> 英文原文:http://developer.android.com/guide/topics/manifest/permission-element.html 采 ...
- SpringCloud IDEA 教学 (一) Eureka的简介与服务注册中心的建立
写在开头 SpringCloud进来成为业界排名靠前的微服务框架,最核心功能就是搭建微服务,并在此基础上衍生出一系列功能,如断路器(Hystrix).断路监控.管理配置.Zuul.OAuth2等功能. ...
- 【转】NodeJS on Nginx: 使用nginx反向代理处理静态页面
最近OurJS后台已经从纯node.js迁移到了Nginx+NodeJS上来了,感觉性能提升了不少,特与大家分享. Nginx ("engine x") 是一个高性能的 HTTP ...
- Thunder团队第六周 - Scrum会议5
Scrum会议5 小组名称:Thunder 项目名称:i阅app Scrum Master:翟宇豪 工作照片: 胡佑蓉同学在拍照,所以不在照片内. 参会成员: 王航:http://www.cnblog ...
- 基于spec评论“欢迎来怼”团队Alpha版作品
“欢迎来怼”团队的作品是手机版博客园 1.获取此博客园app的方式——二维码 通过扫描二维码的方式下载app,这是当今比较流行的方式,适合广大手机的使用者——青少年的使用习惯. 2.点击图标,进入该a ...
- wwnjld团队第二轮迭代成员分数
2014-01-05 第二轮迭代团队内成员分数如下(依据分数分配规则以及团队会议协商所得结果): 吴渊渊 23 汪仁贵 21.5 高小洲 19.5 聂建 22.5 吕家辉 23.5 程志 10
- C++ 学习笔记之 STL 队列
一. 引言 在算法以及数据结构的实现中,很多地方我们都需要队列(遵循FIFO,先进先出原则). 为了使用队列,我们可以自己用数组来实现队列,但自己写太麻烦不说,并且还很容易出错. 好在C++的STL ...
- Gym - 100851F Froggy Ford kruskal
题目链接: http://acm.hust.edu.cn/vjudge/problem/307216 Froggy Ford Time Limit: 3000MS 题意 青蛙过河,河中有若干个石头,现 ...
- TCP系列25—重传—15、DSACK虚假重传探测
一.DSACK介绍 RFC2883通过指定使用SACK来指示接收端的重复包(duplicate packet)扩展了RFC2018对SACK选项的定义(SACK选项的介绍和示例参考前面内容).RFC2 ...