题目

396. 旋转函数

给定一个长度为 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

题目分析

数学推导

从特殊情况开始

F(0)=0nums[0]+1nums[1]+...+(n2)nums[n2]+(n1)nums[n1]F(0) = 0 \cdot nums[0]+1 \cdot nums[1]+...+(n-2)\cdot nums[n-2]+(n-1)\cdot nums[n-1]

F(1)=1nums[0]+2nums[1]+...+(n1)nums[n2]+0nums[n1]F(1) = 1 \cdot nums[0]+2 \cdot nums[1]+...+(n-1)\cdot nums[n-2]+0 \cdot nums[n-1]

F(2)=2nums[0]+3nums[1]+...+(n1)nums[n3]+0nums[n2]+1nums[n1]F(2) = 2 \cdot nums[0]+3 \cdot nums[1]+...+(n-1)\cdot nums[n-3]+0\cdot nums[n-2]+1 \cdot nums[n-1]

F(1)F(0)=nums[0]+nums[1]+...+nums[n1]+0nums[n1](n1)nums[n1]F(1)-F(0)=nums[0]+nums[1]+...+nums[n-1]+0\cdot nums[n-1]-(n-1)\cdot nums[n-1]

F(2)F(1)=nums[0]+nums[1]+...+nums[n3]+0nums[n3](n1)nums[n2]+nums[n1]F(2)-F(1)=nums[0]+nums[1]+...+nums[n-3]+0\cdot nums[n-3]-(n-1)\cdot nums[n-2]+nums[n-1]

S=nums[0]+nums[1]+...+nums[n]S=nums[0]+nums[1]+...+nums[n]

F(1)=F(0)+Snums[n1](n1)nums[n1]=F(0)+Snnums[n1]F(1)=F(0)+S-nums[n-1]-(n-1)\cdot nums[n-1]=F(0)+S-n\cdot nums[n-1]

F(2)=F(1)+Snnums[n2]F(2)=F(1)+S-n\cdot nums[n-2]

归纳到一般情况

更一般地,当1k<n1 \le k \lt n有如下关系成立

F(k)=F(k1)+Snnums[nk]F(k)=F(k-1)+S-n\cdot nums[n-k]

这就是我们的状态转移方程。

特别地,当k=0时,需要单独计算

F(0)=0nums[0]+1nums[1]+2nums[2]+...+(n1)nums[n1]F(0)=0 \cdot nums[0]+1 \cdot nums[1]+2 \cdot nums[2]+...+(n-1) \cdot nums[n-1]

代码实现

根据题目分析,显然我们可以直接写出如下代码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int maxRotateFunction(vector<int>& nums) {
int n = nums.size();
int S = 0;
int F0 = 0;
for(int i=0;i<n;i++){
S+=nums[i];
F0 += i * nums[i];
}
vector<int> F(n);
F[0] = F0;
int maxF = F0;
for(int k=1;k<n;k++) {
F[k] = F[k-1]+S-n*nums[n-k];
maxF = max(maxF, F[k]);
}
return maxF;
}
};

时间复杂度: O(n)O(n)

空间复杂度: O(n)O(n)

由于下一步的状态转移只依赖了前一个状态,故空间复杂度可使用滚动数组优化如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public:
int maxRotateFunction(vector<int>& nums) {
int n = nums.size();
int S = 0;
int F0 = 0;
for(int i=0;i<n;i++){
S+=nums[i];
F0 += i * nums[i];
}
int F[2];
F[0] = F0;
int maxF = F0;
for(int k=1;k<n;k++) {
F[k % 2] = F[(k-1) % 2]+S-n*nums[n-k];
maxF = max(maxF, F[k % 2]);
}
return maxF;
}
};

时间复杂度: O(n)O(n)

空间复杂度: O(1)O(1)