剑指offer(C++)——数据流中的中位数
来源:互联网 发布:如何投诉淘宝客服态度 编辑:程序博客网 时间:2024/06/05 12:41
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路:由于数据是从数据流中读取出来的,数据的个数随着时间的变化而增加。因此我们需要一个数据容器来保存读取出来的数据。
解法1:用数组来保存数据。如果数组无序,则找到中位数最优的算法时间复杂度为O(n),插入一个数字的时间复杂度为O(1);
解法2:还可以让数组一直保持有序,有可能需要移动O(n)个数,因此插入一个数字的时间复杂度为O(n),找到中位数只需O(1)时间即可完成;
解法3:用排序的链表来保存数据。插入一个数字需要O(n)时间,如果定义两个指针指向链表中间的结点,找到中位数只需O(1)时间;
解法4:用二叉搜索树保存数据。插入和查找中位数平均时间可以做到log(n),最坏情况下同样需要O(n)时间;
解法5:用AVL树。稍微修改可以做到用O(logn)时间插入一个数字,O(1)时间得到中位数;
如果数据在容器中已经排好序,那么中位数可以有P1和P2指向的数得到。如果数据个数为奇数个,则P1和P2指向同一个数。
通过观察发现,整儿数据容器被分隔成两部分,位于容器左边的数比右边的数小,而且,P1指向的数据是左边部分最大数,P2指向的数据是右边部分最小数。这一发现很重要,即使P1左边和P2右边的数据没有排序,我们也可以根据左边最大值和右边最小值来得到中位数。那么如何才能快速得到一个容器中的最大值和最小值呢?我们先到了大顶堆和小顶堆。
解法6:用大顶堆实现左边的的数据容器,小顶堆实现右边的数据容器。往堆中插入一个数据时间复杂度为O(logn),而得到最大值(或最小值)只需O(1)时间。有一点需要注意,我们要保证数据被平均分配到两个堆中(想想为什么?),因此两堆大小之差不能超过1。实现方法是数据流中奇数位的数插入小顶堆中,偶数位的数插入大顶堆中。同时还要保证大顶堆中的所有数都要小于小顶堆中的数。考虑一种特殊情况,例如,插入偶数位的数,按照分配规则应该插入大顶堆中,但是这个数大于小顶堆的最小值怎么办?如果直接插入大顶堆,就不符合大顶堆所有值都小于小顶堆的值这一条件。可以这样解决:想把该数插入小顶堆,然后进行堆排序,接着讲小顶堆的最小值拿出来插入到大顶堆中,这样就满足所有条件了。同理插入奇数位的数时也要考虑这种特殊情况。
代码实现如下:
class Solution {public://插入原则:奇数位的数插入小顶堆,偶数位数的插入大顶堆,除特殊情况外void Insert(int num){/*特殊情况1:当插入奇数位的数num时,应插入小顶堆里,但是当num小于大顶堆的最大值时,应将其插入大顶堆,然后将大顶堆的最大值插入小顶堆中*/if (((min.size() + max.size()) & 1) == 0) {if (max.size() > 0 && num < max[0]){max.push_back(num);push_heap(max.begin(), max.end()); //进行堆排序num = max[0]; //找到最大值pop_heap(max.begin(), max.end()); //将最大值移除堆(其实就是将最大值放在数组最后一位)max.pop_back(); //删除}min.push_back(num);push_heap(min.begin(), min.end(),greater<int>()); //构建小顶堆}else{/*特殊情况2:当插入偶数位的数num时,应插入大顶堆里,但是当num大于小顶堆的最小值时,应将其插入小顶堆,然后将小顶堆的最小值插入大顶堆中*/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());}}double GetMedian(){int size = min.size() + max.size();if (size == 0)return 0;if ((size & 1) == 1)return min[0];elsereturn (double)(max[0] + min[0]) / 2;}private:vector<int> min; //用来模拟小顶堆vector<int> max; //用来模拟大顶堆};
关于heap算法可参考:http://blog.csdn.net/yf_li123/article/details/70242850
- 剑指offer(C++)——数据流中的中位数
- 剑指offer——数据流中的中位数
- 剑指offer—数据流中的中位数
- 剑指offer — 数据流中的中位数
- 剑指offer—数据流中的中位数
- 剑指offer(60)-数据流中的中位数
- 剑指offer——64.数据流中的中位数
- 剑指offer--数据流中的中位数
- 《剑指offer》数据流中的中位数
- 剑指offer:数据流中的中位数
- 剑指offer-数据流中的中位数
- 剑指offer 数据流中的中位数
- 《剑指offer》数据流中的中位数
- 剑指Offer:数据流中的中位数
- 剑指offer-数据流中的中位数
- 剑指offer 数据流中的中位数
- 剑指offer——数据流中的中位数(好)(PriorityQueue,Comparator)
- 剑指offer(65):获取数据流中的中位数
- 【bzoj1208】[HNOI2004]宠物收养所
- node2
- Predix之玩转树莓派(1) 准备树莓派
- 浅谈jQuery源码(一)——$.trim
- WHU Contest Problem J.
- 剑指offer(C++)——数据流中的中位数
- 华为李航:NLP 有 5 个基本问题,深度学习有4个做得很好
- Java注解的学习---深入理解Java注解、自己写一个Java注解
- ANDROID 一个app中有多个activity读取NFC标签问题
- Android studio添加第三方类库时出现的版本不兼容问题
- zz的成长
- Linux更改ssh服务远程登录配置
- EL表达式
- 【SSH进阶之路】Struts + Spring + Hibernate 进阶开端(一)