一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
题目链接:396. 旋转函数
题目描述
给定一个长度为 n 的整数数组 nums 。
假设 是数组 nums 顺时针旋转 k 个位置后的数组,我们定义 nums 的 旋转函数 F 为:
返回 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
整理题意
给定一个整数数组,将数组不断旋转(这里的旋转就是将数组第一个元素放到末尾或者是将末尾元素放到数组首部所形成的新数组),每次旋转后将数组的每个整数乘以对应的下标(下标从 0 开始),然后求和,取最大值。
解题思路分析
习惯性动作,首先明确数据范围:
如果暴力解决时间复杂度为 ,显然会 TLE 超时。再确定题目数据是否会溢出,这里题目直接给出了提示,保证生成的测试用例让答案符合 32 位 整数。
我们假设每次旋转操作都是 将数组第一个元素放到末尾,观察每次的求和区间:
这里 total 表示 i * nums[i](i ∈ [1, n))的求和,sum 表示 nums[i](i ∈ [1, n))的和,当我们对数组进行旋转时:
观察旋转后我们可以发现:
total值的变化:减少的值相当于旋转前的sum,增加了(n - 1) * nums[0]sum值的变化:减少了nums[1],增加了nums[0]。 我们可以将情况一般化:total值的变化:减少的值相当于旋转前的sum,增加了(n - 1) * nums[i - 1]sum值的变化:减少了nums[i],增加了nums[i - 1]。 那么我们可以通过一次遍历维护total和sum的值,求得total的最大值即为答案。
具体实现
我们假设 n 为数组长度,total 为每个整数乘以对应的下标的和,sum 为 nums[1] 到 nums[n - 1] 的求和。
- 通过遍历一次
nums数组求得total和sum的初始值。 - 再从
1遍历到n - 1,每次维护total和sum的值:total -= sum;:每次减去上一轮的sum;total += (n - 1) * nums[i - 1];相当于把nums[i - 1]旋转到数组尾部;sum -= nums[i];:将nums[i]旋转到下标为0的位置;sum += nums[i - 1];将nums[i - 1]旋转到数组尾部。
- 期间用
ans记录total的最大值即可:ans = max(ans, total);
复杂度分析
- 时间复杂度:,其中
n是数组nums的长度。计算第一个sum和total消耗 时间,后续迭代n−1次消耗 时间。 - 空间复杂度:。仅使用常数空间。
代码实现
class Solution {
public:
int maxRotateFunction(vector<int>& nums) {
//n为数组长度
int n = nums.size();
//sum为nums数组中下标为[1, n)的和
int sum = 0;
//total为当前选择函数F的值
int total = 0;
//初始化sum和total
for(int i = 1; i < n; i++){
sum += nums[i];
total += (i * nums[i]);
}
//ans记录答案,也就是最大的total
int ans = total;
//不断旋转数组
for(int i = 1; i < n; i++){
//total每次减去[1, n)的和sum
total -= sum;
//total每次加上(n - 1) * nums[i - 1],相当于把nums[i - 1]旋转到数组尾部
total += (n - 1) * nums[i - 1];
//更新sum的值,将nums[i]的值删除,增加nums[i - 1]的值
sum -= nums[i];
sum += nums[i - 1];
//记录total的最大值
ans = max(ans, total);
}
return ans;
}
};
总结
该题的 核心思想是迭代,在迭代过程中维护 total 和 sum 的值,记录 total 最大值即可,没有特殊样例以及坑点。需要注意的细节是答案的初始化和维护变量过程中的修改顺序。
结束语
很多人都觉得优秀是因为有天赋。其实,天赋异禀的人很少,真正让他们出类拔萃的是全心投入和用心付出。拥有得天独厚的优势固然重要,但更多时候,优秀靠的是日复一日的坚持努力。