剑指41:数据流中的中位数

Posted rookiez

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指41:数据流中的中位数相关的知识,希望对你有一定的参考价值。

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。

例如,

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

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

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

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

 

有几种方法可以选取:

1.数组

如果插入时排序,时间复杂度为n,获取中位数的时间复杂度为1

如果插入时不排序,则时间复杂度为1,获取中位数时间复杂度为n

 

2.链表

排序的链表,插入时间复杂度为n,获取时间复杂度为1(用指针记录中位数位置)

 

3.二叉树

使用二叉搜索树,插入平均logn,最差n,查找时间同样

AVL树插入时间复杂度为logn,查找为1

但是这两个太复杂,不适合面试使用

 

4.最大堆和最小堆

将数组分为两部分,前半部分用最大堆,后半部分用最小堆,这样可以在logn的时间内插入,而且在1时间内获取到中位数

如果当前长度为偶数,就加入到最小堆;如果是奇数,就加入到最大堆,保证两个堆节点数量差不超过1

但是要保证最大堆的数据都小于等于最小堆的数据。

如果需要插入到最大堆,但是数据大于最小堆的根节点,即最小堆中最小的值,那么就先把该数加入到最小堆中,然后获取最小堆的根节点,加入到最大堆中。

反过来同理。

使用vector存储数据,用push_heap和pop_heap调整堆。

最大堆时push第三个参数为less<T>(),最小堆为greater<T>(),默认为最大堆。

 1 class MedianFinder {
 2 private:
 3     vector<int> min;
 4     vector<int> max;
 5 public:
 6 
 7     /** initialize your data structure here. */
 8     MedianFinder() {
 9         cout<<"created medianfinder"<<endl;
10     }
11     
12     void addNum(int num) {
13         if(!((min.size()+max.size())&1)){
14             if(max.size()!=0 && num<max[0]){
15                 max.push_back(num);
16                 push_heap(max.begin(),max.end(),less<int>());
17                 num=max[0];
18                 pop_heap(max.begin(),max.end(),less<int>());
19                 max.pop_back();
20             }
21             min.push_back(num);
22             push_heap(min.begin(),min.end(),greater<int>());
23         }
24         else{
25             if(min.size()!=0 && num>min[0]){
26                 min.push_back(num);
27                 push_heap(min.begin(),min.end(),greater<int>());
28                 num=min[0];
29                 pop_heap(min.begin(),min.end(),greater<int>());
30                 min.pop_back();
31             }
32             max.push_back(num);
33             push_heap(max.begin(),max.end(),less<int>());
34         }
35     }
36     
37     double findMedian() {
38         if(min.size()==0)
39             return 0.0;
40         if(!((min.size()+max.size())&1))
41             return (double)(min[0]+max[0])/2;
42         return min[0];
43     }
44 };
45 
46 /**
47  * Your MedianFinder object will be instantiated and called as such:
48  * MedianFinder* obj = new MedianFinder();
49  * obj->addNum(num);
50  * double param_2 = obj->findMedian();
51  */

 

以上是关于剑指41:数据流中的中位数的主要内容,如果未能解决你的问题,请参考以下文章

剑指41:数据流中的中位数

剑指offer41. 数据流中的中位数

剑指offer41数据流中的中位数

剑指Offer面试题41. 数据流中的中位数

剑指Offer面试题41. 数据流中的中位数

每日一题 - 剑指 Offer 41. 数据流中的中位数