数据流中的中位数

题目描述

  如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
  解法1:数组不排序,基于Partition函数找中位数。插入数字和找出中位数的时间复杂度分别为O(1)和O(n)
 1 class Solution {
 2 public:
 3     int Partition(vector<int> &arr, int begin, int end)
 4     {
 5         int tmp=arr[begin];
 6         while(begin<end)
 7         {
 8             while(begin<end && arr[end]>=tmp)--end;
 9             arr[begin]=arr[end];
10             while(begin<end && arr[begin]<=tmp)++begin;
11             arr[end]=arr[begin];
12         }
13         arr[begin]=tmp;
14         return begin;
15     }
16     void Insert(int num)
17     {
18         arr.push_back(num);
19     }
20     double GetMedian()
21     {
22         int length=arr.size();
23         if(length==0)return 0;
24         if(length & 1)
25         {
26             int begin=0;
27             int end=length-1;
28             while(true)
29             {
30                 int mid=Partition(arr, begin, end);
31                 if(mid==length/2)break;
32                 if(mid>length/2)end=mid-1;
33                 else begin=mid+1;
34             }
35             return arr[length/2];
36         }else{
37             int begin=0;
38             int end=length-1;
39             while(true)//确定length/2位置上的数
40             {
41                 int mid=Partition(arr, begin, end);
42                 if(mid==length/2)break;
43                 if(mid>length/2)end=mid-1;
44                 else begin=mid+1;
45             }
46             begin=0;
47             end=length/2-1;
48             while(true)//确定length/2-1位置上的数
49             {
50                 int mid=Partition(arr, begin, end);
51                 if(mid==end)break;
52                 else begin=mid+1;
53             }
54             return (arr[length/2-1]+arr[length/2])*1.0/2;
55         }
56     }
57 private:
58     vector<int> arr;
59 };

  解法2:数组插入元素后保持排序,故插入数字和找出中位数的时间复杂度分别为O(n)和O(1)

 1 class Solution {
 2 public:
 3     void Insert(int num)
 4     {
 5         arr.push_back(num);
 6         size_t idx;
 7         for(idx=arr.size()-2; idx>=0; --idx)//后移
 8         {
 9             if(arr[idx]>num)arr[idx+1]=arr[idx];
10             else break;
11         }
12         arr[idx+1]=num;//插入
13     }
14     double GetMedian()
15     { 
16         int length=arr.size();
17         if(length & 1)
18         {
19             return arr[length/2];
20         }else{
21             return (arr[length/2-1]+arr[length/2])*1.0/2;
22         }
23     }
24 private:
25     vector<int> arr;
26 };

  解法3:用一个大顶堆实现数组左边的数据容器,用一个小顶堆实现数组右边的数据容器。插入数字和找出中位数的时间复杂度分别为O(logn)和O(1)

 1 class Solution {
 2 public:
 3     void Insert(int num)
 4     {
 5         if((max.size()+min.size()) & 1)//如果总数是奇数个,插入大顶堆,并保证大顶堆的所有数据都小于小顶堆中的数据
 6         {
 7             if(min.size()>0 && num>min[0])
 8             {
 9                 min.push_back(num);
10                 push_heap(min.begin(), min.end(), std::greater<int>());
11                 num=min[0];
12                 pop_heap(min.begin(), min.end(), std::greater<int>());
13                 min.pop_back();
14             }
15             max.push_back(num);
16             push_heap(max.begin(), max.end(), std::less<int>());
17         }else{//如果总数是偶数个,插入小顶堆,并保证大顶堆中所有数据都小于小顶堆中的数据
18             if(max.size()>0 && num<max[0])
19             {
20                 max.push_back(num);
21                 push_heap(max.begin(), max.end(), std::less<int>());
22                 num=max[0];
23                 pop_heap(max.begin(), max.end(), std::less<int>());
24                 max.pop_back();
25             }
26             min.push_back(num);
27             push_heap(min.begin(), min.end(), std::greater<int>());
28         }
29     }
30     double GetMedian()
31     {
32         if(min.size()==0)return 0;
33         if((min.size()+max.size()) & 1)
34         {
35             return min[0];
36         }else{
37             return (min[0]+max[0])*1.0/2;
38         }
39     }
40 private:
41     vector<int> max;
42     vector<int> min;
43 };

 

posted @ 2017-12-27 14:19  jeysin  阅读(134)  评论(0编辑  收藏  举报