题目形容
这是 LeetCode 上的 396. 旋转函数 ,难度为 中等。
Tag :「前缀和」、「滑动窗口」
给定一个长度为 $n$ 的整数数组 $nums$。
假如 $arr_k$ 是数组 $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 <= 10^5$
- $-100 <= nums[i] <= 100$
前缀和 + 滑动窗口
为了不便,咱们将 $nums$ 的长度记为 $n$。
题目要对「旋转数组」做逻辑,容易想到将 $nums$ 进行复制拼接,失去长度为 $2 \times n$ 的新数组,在新数组上任意一个长度为 $n$ 的滑动窗口都对应了一个旋转数组。
而后思考在窗口的滑动过程中,计算结果会如何变动,假如以后咱们解决到下标为 $[i, i + n – 1]$ 的滑动窗口,依据题意,以后后果为:
$$
cur = nums[i] \times 0 + nums[i + 1] \times 1 + … + nums[i + n – 1] \times (n – 1)
$$
当窗口往后挪动一位,也就是窗口的右端点来到 $i + n$ 的地位,左端点来到 $i + 1$ 的地位。
咱们须要减少「新右端点」的值,即减少 $nums[i + n] \times (n – 1)$,同时减去「旧左端点」的值,即缩小 $nums[i] \times 0$(固定为 $0$),而后更新新旧窗口的公共局部 $[i + 1, i + n – 1]$。
不难发现,随着窗口的逐渐右移,每一位公共局部的权值系数都会进行减一。
$$
nums[i + 1] \times 1 + nums[i + 2] \times 2 + … + nums[i + n – 1] \times (n – 1)
$$
变为
$$
nums[i + 1] \times 0 + nums[i + 2] \times 1 + … + nums[i + n – 1] \times (n – 2)
$$
因而,公共局部的差值为 $\sum_{idx = i + 1}^{i + n – 1}nums[idx]$,这疏导咱们能够应用前缀和进行优化。
至此,咱们从旧窗口到新窗口的过渡,都是 $O(1)$,整体复杂度为 $O(n)$。
实现上,咱们并不需要真正对 $nums$ 进行复制拼接,而只须要在计算前缀和数组 $sum$ 进行简略的下标解决即可。
代码:
class Solution {public int maxRotateFunction(int[] nums) {
int n = nums.length;
int[] sum = new int[n * 2 + 10];
for (int i = 1; i <= 2 * n; i++) sum[i] = sum[i - 1] + nums[(i - 1) % n];
int ans = 0;
for (int i = 1; i <= n; i++) ans += nums[i - 1] * (i - 1);
for (int i = n + 1, cur = ans; i < 2 * n; i++) {cur += nums[(i - 1) % n] * (n - 1);
cur -= sum[i - 1] - sum[i - n];
if (cur > ans) ans = cur;
}
return ans;
}
}
- 工夫复杂度:$O(n)$
- 空间复杂度:$O(n)$
最初
这是咱们「刷穿 LeetCode」系列文章的第 No.396
篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,局部是有锁题,咱们将先把所有不带锁的题目刷完。
在这个系列文章外面,除了解说解题思路以外,还会尽可能给出最为简洁的代码。如果波及通解还会相应的代码模板。
为了不便各位同学可能电脑上进行调试和提交代码,我建设了相干的仓库:https://github.com/SharingSou…。
在仓库地址里,你能够看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其余优选题解。
更多更全更热门的「口试 / 面试」相干材料可拜访排版精美的 合集新基地 🎉🎉
本文由 mdnice 多平台公布