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. 初涉 JavaScript

    网页是什么 网页 = Html+CSS+JavaScriptHtml:网页元素内容CSS:控制网页样式JavaScript:操作网页内容,实现功能或者效果 JavaScirpt 发展历史 参考 使用 ...

  2. 剑指offer-字符串的排列26

    题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述: 输 ...

  3. Java进阶——— 线程池的原理分析

    前言 在了解线程池之前,其实首先出现的疑问是:为什么要使用线程池,其次是了解什么是线程池,最后是如何使用线程池,带着疑问去学习. 为什么要使用 前面多线程文章中,需要使用线程就开启一个新线程,简单方便 ...

  4. 2018科大讯飞AI营销算法大赛全面来袭,等你来战!

    AI技术已成为推动营销迭代的重要驱动力.AI营销高速发展的同时,积累了海量的广告数据和用户数据.如何有效应用这些数据,是大数据技术落地营销领域的关键,也是检测智能营销平台竞争力的标准. 讯飞AI营销云 ...

  5. Python3 Tkinter-Toplevel

    1.创建 Toplevel与Frame类似,但是它包含窗体属性(如Title) from tkinter import * root=Tk() tl=Toplevel() Label(tl,text= ...

  6. Centos6设置DNS

    通过编辑 vi /etc/resolv.conf 设置首选DNS和次要DNS.如下,排在前面的就是首选DNS,后面一行就是次要的DNS服务器DNS vi /etc/resolv.conf namese ...

  7. 软工1816 · Alpha冲刺(4/10)

    团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 完成菜品信息的标定.量化以及整理成csv的任务   接下来的计划 & ...

  8. 总结Canvas和SVG的区别

    参考链接: 菜鸟教程 HTML5 内联SVG 经典面试题(讨论canvas与svg的区别) Canvas SVG 通过 JavaScript 来绘制 2D 图形 是一种使用 XML 描述 2D 图形的 ...

  9. LintCode-371.用递归打印数字

    用递归打印数字 用递归的方法找到从1到最大的N位整数. 注意事项 用下面这种方式去递归其实很容易: recursion(i) { if i > largest number: return re ...

  10. iOS开发多线程编程2 - NSOperation

    1.简介 NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作. NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOpera ...