[ 滑动窗口、找规律 ] 396. 旋转函数

169 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情

每日刷题 2021.04.22

题目描述

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