一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
每日刷题 2021.04.22
- leetcode原题链接:leetcode-cn.com/problems/ro…
- 难度:中等
- 方法:滑动窗口、找规律
题目描述
- 给定一个长度为 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数组拼接起来,查看数组的长度为10 ^ 5,拼接起来的长度为2 * 10 ^ 5,并没有达到10 ^ 6,因此数组是可以存储下的。 - 样例举例:原数组:
[4,3,2,6];拼接后的数组:[4,3,2,6,4,3,2,6] - 解法:记数组长度为
len,那么滑动窗口的长度也应该为len。 - 举例:
- F(0) = [4,3,2,6,4,3,2,6];
- F(1) = [4,3,2,6,4,3,2,6];
- F(2) = [4,3,2,6,4,3,2,6];
- F(3) = [4,3,2,6,4,3,2,6];
- 遍历
nums数组长度个滑动窗口,滑动窗口的开始位置i,结束位置i + len - 1。滑动窗口中的元素,需要依次进行乘法运算,并将所有元素处理后的数值进行相加,得到res。接着需要判断最大值max = -Infinity是否小于res,如果小于,则将max = res。遍历完整个数组后,就可以得到最终的结果。 - 超时(T了):最开始使用滑动窗口的时候,就有思考到可能会超时,主要是滑动窗口中每次计算的值,都直接被抛弃了,下一轮会重新计算。那么此时虽然滑动窗口有重叠的地方,但是都没有充分利用上。因此考虑可以从这里入手优化。
找规律
- 将数组按照顺序手写出来,分析每一层之间的关系,得到如下推算:
F(0)F(1) = F(0) - (sum - 当前的元素值) + 当前的元素值 * (len - 1)F(2) = F(1) - (sum - 当前的元素值) + 当前的元素值 * (len - 1)F(3) = F(2) - (sum - 当前的元素值) + 当前的元素值 * (len - 1)
AC代码
滑动窗口
/**
* @param {number[]} nums
* @return {number}
*/
var maxRotateFunction = function(nums) {
// 4 3 2 6 4 3 2 6
// 滑动窗口,或者滑动窗口走了数组的长度次数后,就要停下来
// 滑动窗口的大小就是数组的长度
// 会超出数组的范围,但是不会超出字符串的范围
let len = nums.length, temp = nums.concat(nums);
let r = len - 1,ans = -Infinity;
for(let i = 0; i < len; i++) {
// i指针是第一个指针
let multi = 0, res = 0;
while(multi < len) {
res += temp[i + multi] * multi;
multi++;
}
if(ans < res) ans = res;
}
return ans;
};
找规律
var maxRotateFunction = function(nums) {
let multi = 0,sum = 0,one = 0;
let len = nums.length;
for(const el of nums) {
sum += el;
one += el * multi;
multi++;
}
let res = 0,max = one;
for(let i = 0; i < len; i++) {
res = one - (sum - nums[i]) + nums[i] * (len - 1);
if(max < res) max = res;
one = res;
}
return max;
};
总结
- 当题目中要求,找出最大值的时候,需要将自己设定的
max = 0,这是针对没有负数的情况,当存在负数的时候,最小值也自然不是0,此时就应该将最小值改为-Infinity。