目录
1. 题目描述
给定一个数组 A,我们可以将它按一个非负整数 K 进行轮调,这样可以使数组变为 A[K], A[K+1], A{K+2], ... A[A.length - 1], A[0], A[1], ..., A[K-1] 的形式。此后,任何值小于或等于其索引的项都可以记作一分。
例如,如果数组为 [2, 4, 1, 3, 0],我们按 K = 2 进行轮调后,它将变成 [1, 3, 0, 2, 4]。这将记作 3 分,因为 1 > 0 [no points], 3 > 1 [no points], 0 <= 2 [one point], 2 <= 3 [one point], 4 <= 4 [one point]。
在所有可能的轮调中,返回我们所能得到的最高分数对应的轮调索引 K。如果有多个答案,返回满足条件的最小的索引 K。
示例 1:
输入:[2, 3, 1, 4, 0]
输出:3
解释:
下面列出了每个 K 的得分:
K = 0, A = [2,3,1,4,0], score 2
K = 1, A = [3,1,4,0,2], score 3
K = 2, A = [1,4,0,2,3], score 3
K = 3, A = [4,0,2,3,1], score 4
K = 4, A = [0,2,3,1,4], score 3
所以我们应当选择 K = 3,得分最高。
示例 2:
输入:[1, 3, 0, 2, 4]
输出:0
解释:
A 无论怎么变化总是有 3 分。
所以我们将选择最小的 K,即 0。
提示:
A 的长度最大为 20000。
A[i] 的取值范围是 [0, A.length)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/smallest-rotation-with-highest-score
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题分析
2.1 暴力方法
从题意来看,所谓的轮调就是循环左移。
对K进行从0到N-1的扫描,对每个K值导致的轮调结果进行元素值与序号值的比较统计。
这样的话,对K的扫描是O(n),每个轮调结果的统计也是O(n),总的时间复杂度是。
代码参见bestRotation1().
2.2 优化方法
对于数组 nums 中的某元素x,当x 所在下标大于或等于x 时,元素记1 分。因此元素 x 记 1 分的下标范围是 [x, n - 1]。假设元素 x 的初始下标为 i,则当轮调索引为k 时,元素 x在轮调后的新的位置索引是,证明如下:
由此可以根据是否成立来根据判断元素x在k轮调后是否有计分。
进一步,为了方便实现,根据i与x的相对大小进行分类讨论后可以去掉求模运算,如下所示:
- 当 i < x 时,
- 当 i >= x 时,
这两种情况的示例如下:
基于此,可以得到实现算法如下:
用一个数组points存储各轮调结果,points[k]对应于轮调索引为k的计分值。
扫描数组中每个元素x,对于落在会使得元素x经过轮调后有计分的范围内的k,将points[k]加一。这样扫描完毕后,points中就存储了所有轮调情况的计分值。最后求最大值即可。如果出现多个等值的时候,取第一个最大值即可(因为题意要求取论调值最小的)。
代码参见bestRotation().
3. 代码实现
import time
from typing import List
import numpy as np
class Solution:
def bestRotation1(self, nums: List[int]) -> int:
N = len(nums)
margin = np.zeros((N,)) # idx - value
r_max = 0
point_max = -float('inf')
for r in range(N):
for i in range(N):
margin[i] = ((i-r)%N) - nums[i]
# print(margin >= 0)
point = sum((margin >= 0).astype('int'))
if point_max < point:
point_max = point
r_max = r
return r_max
def bestRotation(self, nums: List[int]) -> int:
N = len(nums)
points = np.zeros((N,))
for i in range(N):
x = nums[i]
if i < x:
points[i+1:i-x+N+1] += 1
else:
points[0:i-x+1] += 1
points[(i+1):] += 1
# print(i, points)
k_max = 0
point_max = points[0]
for k in range(1,N):
if point_max < points[k]:
point_max = points[k]
k_max = k
return k_max
if __name__ == '__main__':
sln = Solution()
nums = [2, 3, 1, 4, 0]
print('ans = {0}'.format(sln.bestRotation1(nums)))
print('ans = {0}'.format(sln.bestRotation(nums)))
nums = [1, 3, 0, 2, 4]
print('ans = {0}'.format(sln.bestRotation1(nums)))
print('ans = {0}'.format(sln.bestRotation(nums)))
N = 2000
nums = list(np.random.randint(0,N,N))
tStart = time.time()
ans = sln.bestRotation1(nums)
tElapsed = time.time() - tStart
print('ans = {0}, tElapsed = {1} (sec)'.format(ans,tElapsed))
tStart = time.time()
ans = sln.bestRotation(nums)
tElapsed = time.time() - tStart
print('ans = {0}, tElapsed = {1} (sec)'.format(ans,tElapsed))
以上bestRotation()还利用了numpy的运算勉强通过了leetcode的要求。但是排名非常惨淡:
还需要继续努力。。。^-^.