首页 > 其他 > 详细

数据流的中位数

时间:2020-09-20 20:21:01      阅读:47      评论:0      收藏:0      [点我收藏+]

数据流的中位数

问题定义: 不断有数字过来,问在当前所有数字中的中位数是多少

优先队列--堆

我们可以用一个大根堆和一个小根堆分别维护一个有序数,使得小根堆的所有数字都大于大根堆,这就要求小根堆的堆顶要大于等于大根堆的堆顶。
为了求得中位数,我们需要小根堆和大根堆的数字个数相等或相差一。
我们可以用优先队列实现如下:

priority_queue<int>l; //小根堆
priority_queue<int>g; //大根堆
void add(int num)
{
   l.push(num);
   g.push(l.top());
   l.pop();
   if(l.size()<g.size())
   {
      l.push(g.top());
      g.pop();
   }
}
int ask()
{
   return l.size()<g.size()?l.top():(l.top()+g.top())*0.5;
}

解法二--双指针

我们用multiset维护插入的有序集合,用l和r指针指向中位数,那么显然最终的结果是(l+r)*0.5。当数字个数为偶数时,l和r分别指向不同的两个相邻元素,否则指向同一个元素
代码如下:

multiset<int>s
multiset<int>::iterator left,right;
void add(int num)
{
   int n=s.size();
   s.insert(num);
   if(n==0)
      l=r=s.begin();
   else if(n&1) //原来有奇数个
   {
       if(num<(*l))
            l--;
       else if(num>(*l))
            r++;
   }
   else
   {
      if(num>*l&&num<*r)
        l++,r--;
      else if(num<=*l)
        l=--r;
      else
        l++;
   }
}
int ask()
{
    return (*l+*r)*0.5;
}

应用 LCP24

小扣在秋日市集入口处发现了一个数字游戏。主办方共有 N 个计数器,计数器编号为 0 ~ N-1。每个计数器上分别显示了一个数字,小扣按计数器编号升序将所显示的数字记于数组 nums。每个计数器上有两个按钮,分别可以实现将显示数字加一或减一。小扣每一次操作可以选择一个计数器,按下加一或减一按钮。

主办方请小扣回答出一个长度为 N 的数组,第 i 个元素(0 <= i < N)表示将 0~i 号计数器 初始 所示数字操作成满足所有条件 nums[a]+1 == nums[a+1],(0 <= a < i) 的最小操作数。回答正确方可进入秋日市集。

由于答案可能很大,请将每个最小操作数对 1,000,000,007 取余。

思路

我们对等式做一点小小的转化:nums[a]-a==nums[a+1]-(a+1),所以我们最终要得到的是所有的nums[i]-i的数字都相等。那么这个数很显然应该是这些数字的中位数
那么我们可以维护数据流的中位数,但是这样还要依此算下每个位置的代价(与中位数的距离),因此我们不妨直接维护两个堆中所有数字的和。
用l表示小根堆,r表示大根堆,让r的元素与l相等或多一,那么
当有奇数个数字时,代价是l元素的和sum[l]-nm+(n+1)m-sum[r]=sum[l]-sum[r]+m
当有偶数个数字时,代价是l元素的和sum[l]-nm+(n)m-sum[r]=sum[l]-sum[r]

数据流的中位数

原文:https://www.cnblogs.com/flightless/p/13700780.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!