Loading

剑指 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  */

 

参考

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

 

posted @ 2020-11-06 23:38  拾月凄辰  阅读(75)  评论(0编辑  收藏  举报