(nice!!!)LeetCode LCP 24. 数字游戏(中位数、堆、优先队列)

LCP 24. 数字游戏

在这里插入图片描述
在这里插入图片描述
思路:当求解到第i个元素时,即需要区间[0,i]满足x、x+1、……、x+i。那么总的移动次数就是abs(nums[0]-x)+abs(nums[1]-(x+1))+……+abs(nums[i]-(x+i)),即abs(nums[0]-x)+abs((nums[1]-1)-x)+……+abs((nums[i]-i)-x)。这就化简为x到这些点之间的距离之和,要使距离之和最小,就是把x放在中位数上。
在这里考虑到长度可能到达10^5,我们不能用两层循环。那就用两个优先队列维护一个小顶堆和一个大顶堆。这样时间复杂度为0(nlogn)。细节看注释

class Solution {
public:
    const int mod=1e9+7;
    vector<int> numsGame(vector<int>& nums) {
        vector<int> v;
        //大顶堆维护左半段小的数
        priority_queue<int> left;
        //小顶堆维护右半段大的数
        priority_queue<int,vector<int>,greater<int>> right;
        //两边数的和
        long long sum_left=0,sum_right=0;
        for(int i=0;i<nums.size();i++){
        	//得到新的点
            int tmp=nums[i]-i;
            //当前点为偶数,说明前面已经有偶数个点被分配
            if(i%2==0){
            	//先放进右半段更新
                right.push(tmp);
                sum_right+=tmp;
                //获得新的右半段最小值
                tmp=right.top();
                right.pop();
                sum_right-=tmp;
                
				//放入左半段进行更新
                left.push(tmp);
                sum_left+=tmp;
                //获得左半段最大值
                tmp=left.top();
                cout<<tmp<<endl;
                sum_left-=tmp;
                v.push_back((sum_right-sum_left)%mod);
                //这里左半段没有弹出,因为这个多出来的数先放在左半段
                sum_left+=tmp;
            }else{
            	//当前点为奇数,说明前面已经有奇数个点被分配,左半段多一个点
            	//所以先将新的点放进左半段进行更新
                left.push(tmp);
                sum_left+=tmp;
                //获得左半段最大值
                tmp=left.top();
                sum_left-=tmp;
                //这里需要弹出
                left.pop();
				
				//直接放进右半段,这样两边数量相等
                right.push(tmp);
                sum_right+=tmp;
                v.push_back((sum_right-sum_left)%mod);
            }
        }
        return v;
    }
};
  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值