leetcode 295.数据流的中位数 两个大顶堆

leetcode 295.数据流的中位数

原题链接

(同时也是剑指offer面试题41)

题目:

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2

进阶:

如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

解题思路

1. 插入排序

将数据用vector保存,每次插入一个数据后进行一次排序,返回中位数时只要返回数组长度的一半的下标位置即可。
时间复杂度:插入O(n),中位数O(1)。
空间复杂度O(n)。

2. 两个堆

本题的关键在于求中位数,在思路一中,排序好的数组最中间即是求得中位数的值,所以可以用一个最大堆维护左半边数组,一个最小堆维护右半边数组,使得最大堆的堆顶为左半边数组的最大值,最小堆的堆顶为右半边数组的最小值。

class MedianFinder {
private:
    priority_queue<int,vector<int>,less<int>> max_heap;
    priority_queue<int,vector<int>,greater<int>> min_heap;

public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        if(max_heap.empty()) {
            max_heap.push(num);return ;
        }
        if(num>max_heap.top()){//当前插入值比大顶堆顶还大
            if(min_heap.size()>=max_heap.size()){//且小顶堆数量比大顶堆大or等于
                min_heap.push(num);//插入小顶堆
                int tmp=min_heap.top();//弹出插入后的小顶堆最小值
                min_heap.pop();
                max_heap.push(tmp);//插入到大顶堆,保证数量差不会大于1
            }
            else{//小顶堆数量<大顶堆
                min_heap.push(num);
            }
        }
        else{//当前插入值比大顶堆小or等于
            if(max_heap.size()<=min_heap.size()){//大顶堆数量不大于小顶堆数量
                max_heap.push(num);
            }
            else{
                int tmp=max_heap.top();
                max_heap.pop();
                min_heap.push(tmp);
                max_heap.push(num);
            }
        }


    }
    
    double findMedian() {
        double low=max_heap.top();
        //当为列表总数为偶数
        if(max_heap.size()==min_heap.size()){
            double high=min_heap.top();
            return (low+high)/2;
        }
        //否则当列表总数为奇数返回最大堆堆顶
        return low;
    }
};

时间复杂度:插入O(logn),求中位数O(1)。
空间复杂度:O(n)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值