0
点赞
收藏
分享

微信扫一扫

798.得分最高的最小轮调

诗远 2022-03-12 阅读 33

题目

给你一个数组 nums,我们可以将它按一个非负整数 k 进行轮调,这样可以使数组变为 [ n u m s [ k ] , n u m s [ k + 1 ] , . . . n u m s [ n u m s . l e n g t h − 1 ] , n u m s [ 0 ] , n u m s [ 1 ] , . . . , n u m s [ k − 1 ] ] [nums[k], nums[k + 1], ... nums[nums.length - 1], nums[0], nums[1], ..., nums[k-1]] [nums[k],nums[k+1],...nums[nums.length1],nums[0],nums[1],...,nums[k1]]的形式。此后,任何值小于或等于其索引的项都可以记作一分。

例如,数组为 n u m s = [ 2 , 4 , 1 , 3 , 0 ] nums = [2,4,1,3,0] nums=[2,4,1,3,0],我们按 k = 2 k=2 k=2 进行轮调后,它将变成 [ 1 , 3 , 0 , 2 , 4 ] [1,3,0,2,4] [1,3,0,2,4]。这将记为 3 3 3 分,因为 1 > 0 1 > 0 1>0 [不计分]、 3 > 1 3 > 1 3>1 [不计分]、 0 < = 2 0 <= 2 0<=2 [计 1 分]、 2 < = 3 2 <= 3 2<=3 [计 1 分], 4 < = 4 4 <= 4 4<=4 [计 1 分]。

在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调下标 k k k 。如果有多个答案,返回满足条件的最小的下标 k k k

样例1

输入:nums = [2,3,1,4,0]
输出:3
解释:
下面列出了每个 k 的得分:
k = 0, nums = [2,3,1,4,0], score 2
k = 1, nums = [3,1,4,0,2], score 3
k = 2, nums = [1,4,0,2,3], score 3
k = 3, nums = [4,0,2,3,1], score 4
k = 4, nums = [0,2,3,1,4], score 3
所以我们应当选择 k = 3,得分最高。

样例2

输入:nums = [1,3,0,2,4]
输出:0
解释:
nums 无论怎么变化总是有 3 分。
所以我们将选择最小的 k,即 0。

数据范围

1 <= nums.length <= 1 0 5 10^{5} 105
0 <= nums[i] < nums.length

题解

考虑到每一个数 n u m s [ i ] nums[i] nums[i]在连续下标范围 0 0 0 ~ n u m s [ i ] nums[i] nums[i]对答案的贡献为1,所以我们可以采用的方法是对每一个数,已知其有贡献的下标范围,求出该下标范围对应的 k k k的范围,令此范围内的 p o i n t point point++( p o i n t [ i ] point[i] point[i]记录下标为 i i i k k k的个数)。很显然此时再统计最大的 p o i n t [ i ] point[i] point[i]中最小的 i i i即为答案。

为什么想用这种方法

唯一能够解释这种方法可行的原因在于: n u m s [ i ] nums[i] nums[i]有贡献的下标范围连续,导致对应的 k k k的范围也是连续的,又因为贡献相当于对一个连续片段+1,使用差分数组可以将单点时间复杂度降到 O ( 1 ) O(1) O(1)

难点

想法 + 求对应的 k k k的范围

1.易知元素 x x x 的初始下标为 i i i,则当轮调下标为 k k k 时,元素 x x x 位于下标 ( i − k + n )   m o d   n (i−k+n) mod~n (ik+n)mod n

2.易知元素 x x x 1 1 1 分的下标有 n − x n−x nx

推导出

i < x i<x i<x 时, i + 1 ≤ k ≤ i − x + n i+1≤k≤i−x+n i+1kix+n

i ≥ x i≥x ix 时, k ≥ i + 1 k≥i+1 ki+1 k ≤ i − x k≤i−x kix

代码

class Solution {
public:
    int bestRotation(vector<int>& nums) {
        if(nums.size()==0)return 0;
        vector<int> v(nums.size() + 1);
        for(int i=0;i<nums.size();i++)
        {
            if(i>=nums[i])
            {
                v[0]++;
                v[i-nums[i]+1]--;
                v[i+1]++;
                v[nums.size()]--;
            }
            else
            {
                v[i+1]++;
                v[i-nums[i]+nums.size()+1]--;
            }
        }
        int ans = 0;
        int maxn = 0;
        int cnt = 0;
        for(int i=0;i<nums.size();i++)
        {
            ans += v[i];
            if(maxn < ans)
            {
                maxn = ans;
                cnt = i;
            }
        }
        return cnt;
    }
};
举报

相关推荐

0 条评论