zoukankan      html  css  js  c++  java
  • 剑指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  */
  • 相关阅读:
    5059 一起去打CS
    2439 降雨量
    vijos P1037搭建双塔
    4979 数塔
    2596 售货员的难题
    P2342 叠积木
    1540 银河英雄传说
    1051 接龙游戏
    hdu1251
    洛谷P1717 钓鱼
  • 原文地址:https://www.cnblogs.com/rookiez/p/13237772.html
Copyright © 2011-2022 走看看