• 剑指 Offer 41. 数据流中的中位数


    思路

    方法一:简单排序

    将数字存储在可调整大小的容器中。每次需要输出中间值时,对容器进行排序并输出中间值。

    复杂度分析

    时间复杂度:O(nlogn)+O(1)O(nlogn)。

    添加一个数字对于一个有效调整大小方案的容器来说需要花费 O(1) 的时间。
    找到中间值主要取决于发生的排序。对于标准比较排序,这需要 O(nlogn) 时间。

    空间复杂度:O(n) 线性空间,用于在容器中保存输入。除了需要的空间之外没有其他空间(因为通常可以在适当的位置进行排序)。

    方法二:插入排序

    保持输入容器始终排序。

    复杂度分析

    时间复杂度:O(n)+O(logn)≈O(n).

    二分搜索需要花费 O(logn) 时间才能找到正确的插入位置。
    插入可能需要花费 O(n) 的时间,因为必须在容器中移动元素为新元素腾出空间。

    空间复杂度:O(n) 线性空间,用于在容器中保存输入。

    方法三:一个大顶堆 + 一个小顶堆

    一个大顶堆maxHeap, 一个小顶堆minHeap,大顶堆保存前一半的元素,小顶堆保存后一半的元素。

    与此同时,始终保持两个堆的大小之差不超过1。

    为了保证这两个堆大小之差不超过1,对于元素num的插入过程需分为以下3种情况:

    (1) 大顶堆的元素个数 = 小顶堆的元素个数

      两个堆大小相等,如果小顶堆为空或者待插入的元素num≥小顶堆的堆顶元素,则直接把num插入小顶堆中;

      否则,把num插入大顶堆中。

    (2) 大顶堆的元素个数 < 小顶堆的元素个数

      如果待插入的元素num≤小顶堆的堆顶元素,则直接把num插入大顶堆中;

      否则,弹出小顶堆的堆顶元素,并将其插入大顶堆,之后把num插入小顶堆。

    (3) 大顶堆的元素个数 > 小顶堆的元素个数

      如果待插入的元素num≥大顶堆的堆顶元素,则直接把num插入小顶堆中;

      否则,弹出大顶堆的堆顶元素,并将其插入小顶堆,之后把num插入大顶堆。

    复杂度分析

    时间复杂度:O(logn)。堆的插入删除操作都是O(logn)。

    空间复杂度:O(n) 。小顶堆 和大顶堆一共同时保存 n 个元素。

     1 class MedianFinder {
     2 private:
     3     priority_queue<int, vector<int>, greater<int>> minHeap;
     4     priority_queue<int, vector<int>, less<int>> maxHeap;
     5 public:
     6     /** initialize your data structure here. */
     7     MedianFinder() {
     8 
     9     }
    10     
    11     /*始终保持两个堆的大小之差不超过1*/
    12     void addNum(int num) {
    13         if(maxHeap.size() == minHeap.size()) {
    14             /*如果两个堆大小相等*/
    15             if(minHeap.empty()) {
    16                 minHeap.push(num);
    17                 return;
    18             }
    19 
    20             if(num >= minHeap.top()) {
    21                 minHeap.push(num);
    22             } else {
    23                 maxHeap.push(num);
    24             }
    25 
    26         } else if(maxHeap.size() < minHeap.size()) {
    27             /*如果大顶堆的元素少于小顶堆*/
    28             if(num <= minHeap.top()) {
    29                 maxHeap.push(num);
    30             } else {
    31                 maxHeap.push(minHeap.top());
    32                 minHeap.pop();
    33                 minHeap.push(num);
    34             }
    35 
    36         } else {
    37             /*如果大顶堆的元素多于小顶堆*/
    38             if(num >= maxHeap.top()) {
    39                 minHeap.push(num);
    40             } else {
    41                 minHeap.push(maxHeap.top());
    42                 maxHeap.pop();
    43                 maxHeap.push(num);
    44             }
    45         }
    46     }
    47     
    48     double findMedian() {
    49         if(maxHeap.size() == minHeap.size()) {
    50             return (maxHeap.top() + minHeap.top()) / 2.0;
    51         } else if(maxHeap.size() < minHeap.size()) {
    52             return minHeap.top();
    53         } else {
    54             return maxHeap.top();
    55         }
    56     }
    57 };
    58 
    59 /**
    60  * Your MedianFinder object will be instantiated and called as such:
    61  * MedianFinder* obj = new MedianFinder();
    62  * obj->addNum(num);
    63  * double param_2 = obj->findMedian();
    64  */

    参考

    力扣官方题解 - 数据流的中位数

  • 相关阅读:
    hiho#1445 重复旋律5 求子串数量 后缀自动机
    SPOJ LCS2 后缀自动机
    SPOJ-LCS 后缀自动机
    bzoj 3261 最大异或和 可持久化字典树(01树)
    【洛谷1297】单选错位
    【HAOI2008】木棍分割
    【SDOI2016】排列计数
    【HAOI2008】下落的圆盘
    【HAOI2008】硬币购物
    【洛谷5520】青原樱
  • 原文地址:https://www.cnblogs.com/FengZeng666/p/13939531.html
Copyright © 2020-2023  润新知