LCP 24. 数字游戏

题目详情:

小扣在秋日市集入口处发现了一个数字游戏。主办方共有 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 取余。

示例 1:

输入:nums = [3,4,5,1,6,7]

输出:[0,0,0,5,6,7]

解释:
i = 0[3] 无需操作
i = 1[3,4] 无需操作;
i = 2[3,4,5] 无需操作;
i = 3,将 [3,4,5,1] 操作成 [3,4,5,6], 最少 5 次操作;
i = 4,将 [3,4,5,1,6] 操作成 [3,4,5,6,7], 最少 6 次操作;
i = 5,将 [3,4,5,1,6,7] 操作成 [3,4,5,6,7,8],最少 7 次操作;
返回 [0,0,0,5,6,7]

示例 2:

输入:nums = [1,2,3,4,5]

输出:[0,0,0,0,0]

解释:对于任意计数器编号 i 都无需操作。

示例 3:

输入:nums = [1,1,1,2,3,4]

输出:[0,1,2,3,3,3]


解释:
i = 0,无需操作;
i = 1,将 [1,1] 操作成 [1,2][0,1] 最少 1 次操作;
i = 2,将 [1,1,1] 操作成 [1,2,3][0,1,2],最少 2 次操作;
i = 3,将 [1,1,1,2] 操作成 [1,2,3,4][0,1,2,3],最少 3 次操作;
i = 4,将 [1,1,1,2,3] 操作成 [-1,0,1,2,3],最少 3 次操作;
i = 5,将 [1,1,1,2,3,4] 操作成 [-1,0,1,2,3,4],最少 3 次操作;
返回 [0,1,2,3,3,3]

提示:

1 <= nums.length <= 10^5
1 <= nums[i] <= 10^3

解题思路:

题目难点:
1)、如何将计算的操作次数,转化为每个新数据与中位数的距离之间的关系;(分析题目要做的事情
新数据: nums[i] - i ; //nums[a]+1 == nums[a+1],(0 <= a < i) 即 斜率 为: 1 ;

2)、如何选择数据结构,使插入一条数据+ 求中位数所耗费 时间最短;(vector , queue, priority_queue) ;

优化后的解题思路:
1)、根据条件:nums[a]+1 == nums[a+1],(0 <= a < i) ,生成新的数据 nums[i] - i ; 求解为题转化为求 转化为每个新数据与中位数的距离之间的关系
2)、q0:小顶堆是存储 中位数到右侧的数据;
1: 当 访问的数据的个数为奇数的时候,则表示 q0
数据个数要增加一个
增加的时候要要讨论 新进的nums[i] - iq0.top() 的大小比较 ;

	if (q0.top() > tmp) 
    {
        q1.push(tmp) ;
        tmp2 = q1.top() ;
        q1.pop() ;
        q0.push(tmp2) ;
        preNum += tmp2 ;
    }

    else{
    preNum += tmp ;
    q0.push(tmp) ;
	}

2: 当 访问的数据的个数为偶数的时候 ; q0.size() 大小不变,需要讨论,是否需要数据的替换;

{
    if (q0.top() < tmp){
        preNum -= q0.top() ;
        q1.push(q0.top());
        q0.pop() ;
        q0.push(tmp) ;
        preNum += tmp ;
    }else{
        q1.push(tmp) ;
    }
}

3)、preNum: 为了减少计算sum(q0)的耗时做的优化;

4)、midmin :计算当前i下;需要的操作次数;

// midmin :计算需要 操作的次数;
midmin = preNum - q0.size() * tmp  ;
midmin += tmp * q1.size() - Cnum + preNum  ;
ret.push_back(midmin % 1000000007) ;

代码实现1(超时:数据结构选择不当,插入耗时过大):

class Solution {
public:
    int localVector(vector<int>& lnum , int val)
    {
        int fir = 0 , sec = lnum.size() - 1 , mid ;
        while (fir <= sec)
        {
            mid = (fir + sec) >> 1  ;
            if (lnum[mid] == val) return mid + 1 ;
            else if (lnum[mid] > val) sec = mid - 1 ;
            else fir = mid + 1 ;
        }
        return fir ;
    }
    vector<int> numsGame(vector<int>& nums) {
        int i , j ;
        vector<int> ret ;
        long long midmin = 0 , loc = 0 , tmp ;
        vector<int> cha ;
        for(i = 0 ; i < nums.size() ; i ++)
        {
            tmp = nums[i] - i ;
            loc = localVector(cha , tmp) ;
            cha.insert(cha.begin() + loc , tmp) ;
            tmp = cha[cha.size() >> 1] ;
            midmin = 0 ;            
            for(j = 0 ; j < cha.size() ; j ++) midmin += (cha[j] > tmp) ? (cha[j] - tmp) : (tmp - cha[j]) ;
            ret.push_back(midmin % 1000000007) ;
        }

        return ret ;
    }
};
class Solution {
public:
    int localVector(vector<int>& lnum , int val)
    {
        int fir = 0 , sec = lnum.size() - 1 , mid ;
        while (fir <= sec)
        {
            mid = (fir + sec) >> 1  ;
            if (lnum[mid] == val) return mid + 1 ;
            else if (lnum[mid] > val) sec = mid - 1 ;
            else fir = mid + 1 ;
        }
        return fir ;
    }
    vector<int> numsGame(vector<int>& nums) {
        int i , j ;
        vector<int> ret ;
        long long midmin = 0 , loc = 0 , tmp , midloc ;
        vector<int> cha ;
        cha.push_back(nums[0]) ;
        ret.push_back(0) ;
        long long Cnum = nums[0] , preNum = nums[0] ;
        for(i = 1 ; i < nums.size() ; i ++)
        {
            tmp = nums[i] - i ;
            Cnum += tmp ;
            loc = localVector(cha , tmp) ;                
            cha.insert(cha.begin() + loc , tmp) ;
            midloc = (cha.size() - 1) >> 1 ;
            //cout << midloc << '\t' << loc << endl ;
            if (cha.size() & 1)
            {
                if(loc <= midloc) preNum += cha[loc] ;
                else preNum += cha[midloc] ;
            }
            else
            {
                if (loc <= midloc){
                    preNum -= cha[midloc + 1] ;
                    preNum += cha[loc] ;
                }
            }
            tmp = cha[midloc] ;
            midmin = 0 ;  
            midmin = tmp * midloc + tmp - preNum ;
            midmin += Cnum - preNum - tmp * (cha.size() - 1 - midloc)  ;
            ret.push_back(midmin % 1000000007) ;
        }
        return ret ;
    }
};

代码实现2:

class Solution {
public:

    vector<int> numsGame(vector<int>& nums) {
        int i , j ;
        vector<int> ret ; // 存储返回的结果
        priority_queue<int,vector<int>,greater<int>> q0;//小顶堆
        priority_queue <int,vector<int>,less<int>> q1; // 大顶堆
        ret.push_back(0) ;
        q0.push(nums[0]) ;
        long long tmp , tmp2 , midmin;
        long long Cnum = nums[0] , preNum = nums[0] ;
        //ret里每一项的值
        for(i = 1 ; i < nums.size() ; i ++)
        {
        // nums[i] - i 将问题转化为求中位数
            tmp = nums[i] - i ;
            Cnum += tmp ;
            //当访问的数据为奇数个时,q0的个数需要增加一个;
            if ((i + 1) & 1)
            {
                if (q0.top() > tmp) 
                {
                    q1.push(tmp) ;
                    tmp2 = q1.top() ;
                    q1.pop() ;
                    q0.push(tmp2) ;
                    preNum += tmp2 ;
                }
                else{
                    preNum += tmp ;
                    q0.push(tmp) ;
                }
            }
            //当访问的数据为偶数个时,q0数据个数保持不变 ;
            else
            {
                if (q0.top() < tmp){
                    preNum -= q0.top() ;
                    q1.push(q0.top());
                    q0.pop() ;
                    q0.push(tmp) ;
                    preNum += tmp ;
                }else{
                    q1.push(tmp) ;
                }
            }
            tmp = q0.top() ;
            midmin = 0 ;  
            // midmin :计算需要 操作的次数;
            midmin = preNum - q0.size() * tmp  ;
            midmin += tmp * q1.size() - Cnum + preNum  ;
            ret.push_back(midmin % 1000000007) ;
        }

        return ret ;
    }
};

复杂度计算:

空间复杂度 O(n)

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页