面试题_64——数据流中的中位数
2015-09-03 17:18
507 查看
题目描述:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
解题思路:
数据流证明是输入数据大小是动态变化的。
我们要从动态变化的数据流中找现有数据的中位数。首先需要考虑,这些数据流中的数据该怎么存储?
即 用什么数据结构进行存储? 从而最方便查找中位数。
用数组来存储,如果是无序数组,则插入效率O(1) , 查找中位数效率O(n);
如果用有序数组来存储,那么插入O(n),查找中位数效率O(1);
如果用链表来存储,插入O(1),查找O(n);
用二叉搜索树来存储,插入平均O(logn),最差O(n),查找中位数效率平均O(logn),最差O(n);
AVL树,插入O(logn),查找中位数O(1);
最大堆 和 最小堆,插入O(logn),查找中位数O(1).
AVL树在C++STL中没有直接库函数可用,需要自行编写,实现起来比较复杂。
因此,用堆来实现本题目的需求是最佳选择。
利用C++,STL库中,push_heap()、pop_heap()、vector 以及 比较函数 less<type>() 和 greater<type>()
来实现堆得操作。
具体思路如下:
1、维护两个堆,一个小顶堆,一个大顶堆。
max中存储当前数据流中较小的一半;
min中存储当前数据流中较大的一半;
同时,需要满足:max中的所有数据 都 小于 min中存储的所有数据。
(这里要在编程实现的时候做处理,即拿当前的数据与堆顶数据进行比较。然后,拿到符合要求的数据)
这样,数据流中的数据分为两个部分,较大的一部分、较小的一部分。
取中位数就直接取大顶堆堆顶 或 小顶堆堆顶。
当数据流中数据数目是奇数个就插入——>小顶堆;
当数据流中数据数目是偶数个就插入——>大顶堆;
那么,最后,取中位数,奇数就去小顶堆,偶数就取两个堆顶和的平均值。
实现代码:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
解题思路:
数据流证明是输入数据大小是动态变化的。
我们要从动态变化的数据流中找现有数据的中位数。首先需要考虑,这些数据流中的数据该怎么存储?
即 用什么数据结构进行存储? 从而最方便查找中位数。
用数组来存储,如果是无序数组,则插入效率O(1) , 查找中位数效率O(n);
如果用有序数组来存储,那么插入O(n),查找中位数效率O(1);
如果用链表来存储,插入O(1),查找O(n);
用二叉搜索树来存储,插入平均O(logn),最差O(n),查找中位数效率平均O(logn),最差O(n);
AVL树,插入O(logn),查找中位数O(1);
最大堆 和 最小堆,插入O(logn),查找中位数O(1).
AVL树在C++STL中没有直接库函数可用,需要自行编写,实现起来比较复杂。
因此,用堆来实现本题目的需求是最佳选择。
利用C++,STL库中,push_heap()、pop_heap()、vector 以及 比较函数 less<type>() 和 greater<type>()
来实现堆得操作。
具体思路如下:
1、维护两个堆,一个小顶堆,一个大顶堆。
大顶堆max | 小顶堆min |
min中存储当前数据流中较大的一半;
同时,需要满足:max中的所有数据 都 小于 min中存储的所有数据。
(这里要在编程实现的时候做处理,即拿当前的数据与堆顶数据进行比较。然后,拿到符合要求的数据)
这样,数据流中的数据分为两个部分,较大的一部分、较小的一部分。
取中位数就直接取大顶堆堆顶 或 小顶堆堆顶。
当数据流中数据数目是奇数个就插入——>小顶堆;
当数据流中数据数目是偶数个就插入——>大顶堆;
那么,最后,取中位数,奇数就去小顶堆,偶数就取两个堆顶和的平均值。
实现代码:
class Solution { public: void Insert(int num) { if(( (max.size() + min.size()) & 1 ) == 0) { if(max.size() > 0 && num < max[0]) { max.push_back(num); push_heap(max.begin(), max.end(), less<int>()); num = max[0]; pop_heap(max.begin(),max.end(),less<int>()); max.pop_back(); } min.push_back(num); push_heap(min.begin(), min.end(), greater<int>()); } else { if(min.size() > 0 && num > min[0]) { min.push_back(num); push_heap(min.begin(), min.end(),greater<int>()); num = min[0]; pop_heap(min.begin(),min.end(),greater<int>()); min.pop_back(); } max.push_back(num); push_heap(max.begin(),max.end(),less<int>()); } } double GetMedian() { int size = max.size() + min.size(); if(size == 0) { return 0.0; } double median = 0.0; if((size & 1) == 1) { median = static_cast<double>(min[0]); } else { median = static_cast<double>((min[0] + max[0])/2.0); } return median; } private: vector<int> max; vector<int> min; };
相关文章推荐
- 华为Java面试题目总结
- JAVA面试(未完)
- 黑马程序员——面向对象(继承)-第17天
- 10个帮程序员减压放松的网站
- leetcode刷题-Integer to English Words
- 剑指offer——面试题39:扩展问题判断一个树是否是平衡二叉树(递归)
- 腾讯后台开发面试题--整理1
- 【面试】蘑菇街产品运营二面&结果
- 程序员如何在"小公司成长"和"大公司学习"
- 【阿里笔试+蘑菇街面试】向来缘浅,奈何情深
- 一名程序员的自我修养
- 程序员方阵~
- 剑指offer——面试题39:二叉树的深度(递归二叉树,广度优先搜索)
- 剑指offer-第七章面试案例2(树中两个节点的公共祖先节点)
- 剑指offer-第七章面试案例2(树中两个节点的公共祖先节点)
- 剑指Offer面试题:21.从上到下打印二叉树
- 面试总结
- 14条职场生涯建议
- 剑指offer——面试题38:数字在排序数组中出现的次数(利用二分查找来找第一次和最后一次的位置)
- 初学者应该解决的设计模式面试问题