题目
给你一个数组 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.length−1],nums[0],nums[1],...,nums[k−1]]的形式。此后,任何值小于或等于其索引的项都可以记作一分。
例如,数组为 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 (i−k+n) mod n
2.易知元素 x x x 记 1 1 1 分的下标有 n − x n−x n−x 个
推导出
当 i < x i<x i<x 时, i + 1 ≤ k ≤ i − x + n i+1≤k≤i−x+n i+1≤k≤i−x+n;
当 i ≥ x i≥x i≥x 时, k ≥ i + 1 k≥i+1 k≥i+1 或 k ≤ i − x k≤i−x k≤i−x。
代码
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;
}
};