leetcode刷题记录-396. 旋转函数

143 阅读2分钟

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

前言

今天的题目为中等,属于偏向于数学的找规律题目,能够多写出来两个例子,看一下和之间的关系,应该是不难发现其中的规律,再知道了规律之后,这就是一道简单题了。

每日一题

今天的题目是 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

题解

滑动窗口找规律

经典的数学找规律题目,之前我们提到过,一个数组的旋转,可以看为两个这个数组拼接之后的滑动窗口。

image.png

这样每次移动的时候,我们要减去右端点,加上左端点,我们将两倍的数组长度记为2n,现在从n-2n开始往0移动,设第一个窗口的和为 sum

假设当前我们处理到下标为 [n-i-1, 2n-i-1] 的滑动窗口,根据题意,当前结果为:

cur = nums[n-i-1] * 0 + nums[n-i+1-1] * 1 + ... + nums[2n-i-1] * (n - 1)

然后每一次的移动,都会让左端点的值增加一个,右端点的值减少一个,既

next = nums[n-i-1+1] * 0 + nums[n-i+1-1+1] * 1 + ... + nums[2n-i-1+1] * (n - 1)*

我们将两个相减就能够发现

cur-next = nums[n-i-1]+nums[n-i-1+1]+···+nums[2n-i-1]-n*nums[n-i-1]

可以看出 nums[n-i-1]+nums[n-i-1+1]+···+nums[2n-i-1] 就是 sum-nums[n-i-1]

所以最后我们能够得到两个前后方程式的关系

next=cur-sum+n*num[i-1]

然后根据得到的方程式进行迭代就可以得出答案:

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxRotateFunction = function(nums) {
    let n = nums.length
    let cur = [0]
    let sum = 0
    for(let i=0;i<n;i++){
        sum+=nums[i]
        cur[0]+=(i*nums[i])
    }
    let res = cur[0]
    for(let i=1;i<n;i++){
        cur[i] = cur[i-1]-sum+n*nums[i-1]
        res=Math.max(cur[i],res)
    }
    return res
};

image.png