【每日一题】LeetCode 2090.半径为 k 的子数组平均值问题(数组、滑动窗口)
题目描述
给你一个下标从 0 开始的数组 nums
,数组中有 n
个整数,另给你一个整数 k
。
半径为 k 的子数组平均值 是指:nums
中一个以下标 i
为 中心 且 半径 为 k
的子数组中所有元素的平均值,即下标在 i - k
和 i + k
范围(含 i - k
和 i + k
)内所有元素的平均值。如果在下标 i
前或后不足 k
个元素,那么 半径为 k 的子数组平均值 是 -1
。
构建并返回一个长度为 n
的数组 avgs
,其中 avgs[i]
是以下标 i
为中心的子数组的 半径为 k 的子数组平均值 。
x
个元素的 平均值 是 x
个元素相加之和除以 x
,此时使用截断式 整数除法 ,即需要去掉结果的小数部分。
- 例如,四个元素
2
、3
、1
和5
的平均值是(2 + 3 + 1 + 5) / 4 = 11 / 4 = 2.75
,截断后得到2
。
思路分析
- 初始化:创建一个长度与
nums
相同的数组avgs
并初始化所有值为-1
。 - 特殊情况处理:如果
2 * k + 1
大于数组nums
的长度,则直接返回avgs
,因为无法形成有效的子数组。 - 计算平均值:从数组的中间开始,计算以
i
为中心的子数组的和,然后除以子数组的长度(2 * k + 1
)得到平均值,并赋值给avgs[i]
。 - 滑动窗口:随着
i
的增加,更新子数组的和,通过减去窗口左侧超出范围的元素值,加上窗口右侧新进入的元素值。 - 循环:重复上述过程,直到处理完所有可能的子数组。
输入示例
-
示例 1:
- 输入:
nums = [7,4,3,9,1,8,5,2,6]
,k = 3
- 输出:
[-1,-1,-1,5,4,4,-1,-1,-1]
- 输入:
-
示例 2:
- 输入:
nums = [100000]
,k = 0
- 输出:
[100000]
- 输入:
-
示例 3:
- 输入:
nums = [8]
,k = 100000
- 输出:
[-1]
- 输入:
代码实现
class Solution {
public int[] getAverages(int[] nums, int k) {
int n = nums.length;
int[] avgs = new int[n];
Arrays.fill(avgs, -1); // 初始化所有值为 -1
int window = 2 * k + 1; // 子数组的长度
if (window > n) { // 特殊情况处理
return avgs;
}
int start = k, end = n - k - 1; // 定义窗口的起始和结束下标
long sum = 0; // 用于存储子数组的和
for (int i = 0; i < window; i++) {
sum += nums[i]; // 计算窗口内元素的和
}
avgs[start] = (int) (sum / window); // 计算第一个子数组的平均值
for (int i = start + 1; i <= end; i++) {
sum = sum - nums[i - k - 1] + nums[i + k]; // 滑动窗口,更新子数组的和
avgs[i] = (int) (sum / window); // 计算下一个子数组的平均值
}
return avgs;
}
}