[leetcode]798得分最高的最小轮调,差分

题意

现在有一个数组,先不管什么叫轮调(k==0的情况),计算原数组的分数:一个数组中每个元素都有可能得分,得分的条件是元素的值小于等于其索引,即num[i]<=i
轮调:可以改变数组的起点,题目也有样例:数组为 nums = [2,4,1,3,0],我们按 k = 2 进行轮调后,它将变成 [1,3,0,2,4]。这将记为 3 分,因为 1 > 0 [不计分]、3 > 1 [不计分]、0 <= 2 [计 1 分]、2 <= 3 [计 1 分],4 <= 4 [计 1 分]。
现在需要找到某个k使得分数最大,k不唯一的话取最小的k。

思路

暴力枚举k可不可行?反正我不会这么写。
要考虑一个元素是否得分,只需要考虑k取什么值的时候能令到这个数字得分。因为有轮调的存在,num[i]<=i的i是可变的,但num[i]的值却是固定的,可以写成num[i]<=(i-k+n)%n,k为轮调的值,n为数组元素个数。可以看到,要使得不等式成立,k就会有一个取值范围(题目给出的num中的值都小于它的长度,所以是一定有可行域的。)
首先我们要知道k的取值范围是[0,n-1],根据不等式,可以看到,k从0开始变大的话,(i-k+n)%n的值会变小,然后在变大,所以要以i与num[i]的大小关系分类讨论,如果i比num[i]小的话,num[i]能得分的k的取值范围只有[ i+1 , n+i-num[i] ]一段,否则有[ 0 , i-num[i] ]以及[ i+1 , n-1 ]两段。(可以自己举例证明或推理证明)

我们可以在计算每个num[i]的有效的k的取值范围,然后再枚举k的每个值,看k固定时有多少个元素能够得分。答案取能得到最高分的k的最小值

代码

class Solution {
public:
    int bestRotation(vector<int>& nums) {
        int n = nums.size();
        vector<int> sum(n+1,0);
        for(int i = 0;i < n; ++i){
            int nk = nums[i];
            if(i < nk){
                ++sum[1+i];
                --sum[n+i-nk+1];
            }else{
                ++sum[0];
                --sum[i-nk+1];
                ++sum[1+i];
                --sum[n];
            }
        }
        int countNum = 0,ans = 0,maxNum=0;
        for(int i = 0;i < n; ++i){
            countNum += sum[i];
            if(maxNum < countNum){
                maxNum = countNum;
                ans = i;
            }
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值