剑指offer——数据流中的中位数

题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

方法一:
数组插入进去然后再排序,这种情况插入时间效率是O(n),找中位数时间效率是O(1)。

class Solution {
    vector<int> dataStream;
public:
    void Insert(int num)
    {
        dataStream.push_back(num);
        if (dataStream.size() > 1) {
            for (int i = dataStream.size() - 1; i > 0; i--) {
                if (dataStream[i] < dataStream[i-1])
                    swap(dataStream[i], dataStream[i-1]);
            }
        }
    }
    double GetMedian()
    { 
        double Median;
        int len = dataStream.size();
        if (len % 2 != 0)
            return (double)dataStream[len/2];
        else
            return ((double)dataStream[len/2] + (double)dataStream[len/2-1]) / 2;
    }

};

方法二:
大顶堆和小顶堆。插入的时间效率是O(logn),找中位数的时间效率是O(1)。
使用c++ STL优先队列priority_queue:

priority_queue <int,vector<int>,greater<int> > minHeap;//构造小顶堆
priority_queue <int,vector<int>,less<int> > maxHeap;//构造大顶堆

思路:以中位数为分界点将整个输入数据分成两部分;
根据中位数的性质,当输入元素为奇数时,中位数位于存储前半部分数据的大顶堆中;当输入元素为偶数时,中位数位于存储后半部分数据的小顶堆中。在大顶堆中加入元素的后,将大顶堆中的最大的元素(maxHeap.top())加入到小顶堆中,在小顶堆中加入元素的后,将小顶堆中的最小的元素(minHeap.top())加入到大顶堆中。

class Solution {
    int count = 0;
    priority_queue <int,vector<int>,greater<int> > minHeap;
    priority_queue <int,vector<int>,less<int> > maxHeap;
public:
    void Insert(int num)
    {
       count++;
       if (count % 2 != 0) {
           minHeap.push(num);
           maxHeap.push(minHeap.top());
           minHeap.pop();
       } else {
           maxHeap.push(num);
           minHeap.push(maxHeap.top());
           maxHeap.pop();
       }
        
    }
    double GetMedian()
    { 
        if (count % 2 != 0)
            return (double)maxHeap.top();
        else
            return (double)(minHeap.top() + maxHeap.top()) / 2;
    }

};

方法三:
利用头文件algorithm中的make_heap()、push_heap()、pop_heap()
注意在使用以上三个函数是要注明less< int>()(表示降序序列,构造大顶堆),greater< int>()(表示升序序列,构造小顶堆);默认状态是构造大顶堆。
注意:pop_heap()的作用是:交换* first和 * (last-1), 然后把[first, last-1)建成一个max heap(默认状态下). 也就是说把堆顶的最大元素交换到区间尾,然后把除了尾部的元素的剩余区间重新调整成堆。注意此时并不是真正的删除,只是将原堆顶的最大元素交换到区间尾。在本题中需要调用pop_back才能将原堆顶元素彻底删除。

class Solution {
    int count = 0;
    vector<int> minHeap;
    vector<int> maxHeap;
public:
    void Insert(int num)
    {
       count++;
       if (count % 2 != 0) {
           minHeap.push_back(num);
           push_heap(minHeap.begin(), minHeap.end(), greater<int>());
           maxHeap.push_back(minHeap[0]);
           push_heap(maxHeap.begin(), maxHeap.end(), less<int>());
           pop_heap(minHeap.begin(), minHeap.end(), greater<int>());
           minHeap.pop_back();
       } else {
           maxHeap.push_back(num);
           push_heap(maxHeap.begin(), maxHeap.end(), less<int>());
           minHeap.push_back(maxHeap[0]);
           push_heap(minHeap.begin(), minHeap.end(), greater<int>());
           pop_heap(maxHeap.begin(), maxHeap.end(), less<int>());
           maxHeap.pop_back();
       }
    }
    double GetMedian()
    { 
        if (count % 2 != 0)
            return (double)maxHeap[0];
        else
            return (double)(minHeap[0] + maxHeap[0]) / 2;
    }

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值