396. 旋转函数
难度中等243
给定一个长度为 n
的整数数组 nums
。
假设 arrk
是数组 nums
顺时针旋转 k
个位置后的数组,我们定义 nums
的 旋转函数 F
为:
F(k) = 0 * arrk[0] + 1 * arrk[1] + ... + (n - 1) * arrk[n - 1]
返回 F(0), F(1), ..., F(n-1)
中的最大值 。
生成的测试用例让答案符合 32 位 整数。
示例 1:
输入: nums = [4,3,2,6]
输出: 26
解释:
F(0) = (0 * 4) + (1 * 3) + (2 * 2) + (3 * 6) = 0 + 3 + 4 + 18 = 25
F(1) = (0 * 6) + (1 * 4) + (2 * 3) + (3 * 2) = 0 + 4 + 6 + 6 = 16
F(2) = (0 * 2) + (1 * 6) + (2 * 4) + (3 * 3) = 0 + 6 + 8 + 9 = 23
F(3) = (0 * 3) + (1 * 2) + (2 * 6) + (3 * 4) = 0 + 2 + 12 + 12 = 26
所以 F(0), F(1), F(2), F(3) 中的最大值是 F(3) = 26 。
示例 2:
输入: nums = [100]
输出: 0
提示:
n == nums.length
1 <= n <= 105
-100 <= nums[i] <= 100
前缀和 + 滑动窗口
题解:https://leetcode.cn/problems/rotate-function/solution/by-ac_oier-sxbi/
题目要对「旋转数组」做逻辑,容易想到将 n u m s nums nums 进行复制拼接,得到长度为 2 ∗ n 2 * n 2∗n 的新数组,在新数组上任意一个长度为 $n $ 的滑动窗口都对应了一个旋转数组。
当窗口往后移动一位,也就是窗口的右端点来到 i + n i + n i+n 的位置,左端点来到 i + 1 i + 1 i+1 的位置。
不难发现,随着窗口的逐步右移,每一位公共部分的权值系数都会进行减一。
公共部分的差值为 ∑ i d x = i + 1 i + n − 1 n u m s [ i d x ] \sum_{idx = i + 1}^{i + n - 1}nums[idx] ∑idx=i+1i+n−1nums[idx],这引导我们可以使用前缀和进行优化。
至此,我们从旧窗口到新窗口的过渡,都是 O ( 1 ) O(1) O(1),整体复杂度为 O ( n ) O(n) O(n)。
实现上,我们并不需要真正对 n u m s nums nums 进行复制拼接,而只需要在计算前缀和数组 s u m sum sum 进行简单的下标处理即可。
class Solution {
public int maxRotateFunction(int[] nums) {
int n = nums.length;
int[] sum = new int[n*2+1];
for(int i = 1; i <= 2*n; i++){
// (i-1)%n,对下标进行处理,以实现旋转数组2*n的前缀和
sum[i] = sum[i-1] + nums[(i-1)%n];
}
int ans = 0;
for(int i = 1; i <= n; i++){
//根据F的定义,先把初始值求出来
ans += nums[i-1]*(i-1);
}
for(int i = n+1,cur = ans; i < 2*n; i++){
cur += nums[(i-1) % n]*(n-1); // 加上出现在窗口右端点的值(n - 1) * arrk[n - 1]
cur -= sum[i-1] - sum[i-n]; // 权重系数都减了1 = 减去窗口内的和
if(cur > ans) ans = cur;
}
return ans;
}
}
找规律+动态规划
// 找规律题
// sum: a0 * 1 + a1 * 1 + a2 * 1 + a3 * 1
// f(0): a0 * 0 + a1 * 1 + a2 * 2 + a3 * 3
// f(0) + sum: a0 * 1 + a1 * 2 + a2 * 3 + a3 * 4
// f(1): a3 * 0 + a0 * 1 + a1 * 2 + a2 * 3 f(1) = f(0) + sum - 4*a[4-1]
// f(1) + sum: a3 * 1 + a0 * 2 + a1 * 3 + a2 * 4
// f(2): a2 * 0 + a3 * 1 + a0 * 2 + a1 * 3 f(2) = f(1) + sum - 4*a[4-2]
// f(2) + sum: a2 * 1 + a3 * 2 + a0 * 3 + a1 * 4
// f(3): a1 * 0 + a2 * 1 + a3 * 2 + a0 * 3 f(3) = f(2) + sum - 4*a[4-3]
// 由上可得f(n) = f(n - 1) + sum - len * a[len - n]
class Solution:
def maxRotateFunction(self, nums: List[int]) -> int:
n = len(nums)
cur = sum([i * nums[i] for i in range(n)])
ans = cur
total = sum(nums)
for i in range(n - 1):
cur = cur + n * nums[i] - total
if cur > ans:
ans = cur
return ans