算法多解——JZ41 数据流中的中位数(构造大小顶堆)

这篇博客探讨了如何在数据流中实时计算中位数的问题,提出了两种解法。解法一是使用排序,每次插入数据后对容器排序,然后返回中位数;解法二是利用大顶堆和小顶堆,维护数据的平衡,以O(1)的时间复杂度获取中位数。文章详细分析了两种方法的时间和空间复杂度,并给出了具体的代码实现。
摘要由CSDN通过智能技术生成

题面


解法1

思路分享

  • 其实可以说是一道模拟题吧
  • 最常规的思路如下:
  • 结合题意,Insert()方法读取数据就是:逐个把数据流里面的数压入vector容器去处理;
  • GetMedian()方法获取当前读取数据...就是:把当前容器中的数按照要求处理返回中位数
  • 这个要求就是排好序后照常返回中位数

复杂度分析

  • 时间复杂度:寻找中位数操作中,快排复杂度O(nlogn),公式计算中位数复杂度为O(1), 故总体复杂度为O(nlogn)
  • 空间复杂度:录入数据过程中,每个数据只操作一次,复杂度为O(n)

代码呈现

class Solution {
public:
    vector<int> v;
    void Insert(int num) {
        v.push_back(num); //把num元素添加到容器中
    }
    double GetMedian() { 
        sort(v.begin(),v.end());
        int len = v.size();
        if(len%2 != 0)
            return v[(len-1)/2]*1.0; //注意vector从0开始,且输出为浮点数
        else
            return (v[len/2]+v[len/2-1])*1.0/2;
    }
};

解法2

思路分享

构造&大小顶堆

定义两个堆,一个大顶堆Lmax, 一个小顶堆Rmin,分别存放位于中位数左边和中位数自身,位于中位数右边的数据,这样只要问两个堆的堆顶即可获得中位数的结果,由中位数奇偶性质可知:

  • 当已添加的数据个数为奇数时,小顶堆的数据个数比大顶堆多一个,此时若要再添加一个数据,必定添加在小顶堆Rmin上,但不知道当前添加的数是否大于中位数,故先插入Lmax然后将Lmax中的最大数放入Rmin中,同时删除Lmax中的最大数,即删除堆顶。

  • 当已添加的数据个数为偶数时,小顶堆的数据个数等于大顶堆,此时若再添加一个数据,必定添加在大顶堆Lmax上,添加的手段和前者相同。

这样我们便将数据进行了分隔,然后通过O(1)的复杂度访问堆顶即可计算出中位数。

假定录入数据流为[5,3,2,1,4],过程模拟如下:

1. 添加第1个数据,当前已经添加的个数为0个,偶数个,故添加在Lmax上,先将数据5放入Rmin筛出最小值再放入Lmax,同时删除Lmax的最小值。

2. 添加第2个数据,当前已经添加的个数为1个,奇数个,故添加在Rmin上,先将数据3放入Lmax筛出最大值再放入Rmin,同时删除Rmin的最大值。

以下步骤同理...


算法多解——JZ40 最小的K个数(大根堆模拟及手撕)_夏旭的博客-CSDN博客题面解法1(快排)复杂度时间复杂度:O(nlongn),取决于排序的快慢空间复杂度:O(n)思路由于逻辑关系和常理,k<n成立,不用特判。要求最小的k个数,最能直接想到的思路就是:先将这些数排好序,前k个最小的数压入ans数组,最后返回就好了。根据常用习惯,下面就用了sort快排和Vector的push_back解决了。也可以排序后直接 return vector<int>({input.begin(), input.begin()+https://blog.csdn.net/Luoxiaobaia/article/details/122900408?spm=1001.2014.3001.5501

复杂度分析

  • 时间复杂度:使用堆处理数据,每次添加时间复杂度为O(nlogn)
  • 空间复杂度:查询最值复杂度为O(1)

代码呈现

class Solution {
public:
    priority_queue<int> Lmax;
    priority_queue<int, vector<int>, greater<int> > Rmin;
    int cnt = 0;         //记录当前已经添加数据的个数
    void Insert(int num) {
        if(cnt & 1) { //已经添加了奇数个,当前添加至Rmin
            Lmax.push(num);
            Rmin.push(Lmax.top()); 
            Lmax.pop();
        } else { //已经添加了偶数个,当前添加至Lmin
            Rmin.push(num);
            Lmax.push(Rmin.top()); 
            Rmin.pop();
        }
        cnt++;
    }
    double GetMedian() { 
         if(cnt&1) return Lmax.top(); //奇数
         else return (Lmax.top()+Rmin.top())/2.0; //偶数
    }
};

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

米莱虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值