zoukankan      html  css  js  c++  java
  • 数据流的中位数

    数据流的中位数

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

    优先队列--堆

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

    priority_queue<int,vector<int>,greater<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]
    代码如下:

    class Solution {
    public:
        typedef long long ll;
        const int mod=1e9+7;
        vector<int> numsGame(vector<int>& nums) {
            int n=nums.size();
            if(n==1)
                return {0};
            for(int i=0;i<n;i++)
                nums[i]-=i;
            priority_queue<int>g; //大根堆
            priority_queue<int,vector<int>,greater<int>>l; //小根堆
            vector<int>ans;
            l.push(max(nums[0],nums[1]));
            g.push(min(nums[0],nums[1]));
            ll sum0=g.top(),sum1=l.top();
            ans.push_back(0);
            ans.push_back(sum1-sum0);
            for(int i=2;i<n;i++)
            {
                if(nums[i]>l.top())
                {
                    l.push(nums[i]);
                    sum1+=nums[i];
                }
                else if(nums[i]<=g.top())
                {
                    g.push(nums[i]);
                    sum0+=nums[i];
                }
               // cout<<sum0<<" "<<sum1<<endl;
                if(l.size()+2==g.size())
                {
                    l.push(g.top());
                    sum0-=g.top();
                    sum1+=g.top();
                    g.pop();
                }
                else if(l.size()==g.size()+1)
                {
                    g.push(l.top());
                    sum1-=l.top();
                    sum0+=l.top();
                    l.pop();
                }
                //cout<<sum0<<" "<<sum1<<endl;
                ll val=(i%2)?(sum1-sum0):(sum1-sum0+g.top());
                ans.push_back(val%mod);
            }
            return ans;
        }
    };
    
  • 相关阅读:
    Construct Binary Tree from Preorder and Inorder Traversal
    Construct Binary Tree from Inorder and Postorder Traversal
    Maximum Depth of Binary Tree
    Sharepoint 2013 创建TimeJob 自动发送邮件
    IE8 不能够在Sharepoint平台上在线打开Office文档解决方案
    TFS安装与管理
    局域网通过IP查看对方计算机名,通过计算机名查看对方IP以及查看在线所有电脑IP
    JS 隐藏Sharepoint中List Item View页面的某一个字段
    SharePoint Calculated Column Formulas & Functions
    JS 两个一组数组转二维数组
  • 原文地址:https://www.cnblogs.com/flightless/p/13700780.html
Copyright © 2011-2022 走看看