830 字
4 分钟
2090. 半径为 k 的子数组平均值
2090. 半径为 k 的子数组平均值
题目描述
给你一个下标从 0 开始的数组 nums 和一个整数 k。
半径为 k 的子数组平均值是指:对每个下标 i,以下标 i 为中心,半径为 k 的子数组(共 2k+1 个元素)的平均值向下取整。
返回数组 avgs,其中 avgs[i] 是对应下标的平均值,如果无法找到半径为 k 的子数组则返回 -1。
示例 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]提示:
n == nums.length1 <= n <= 10^50 <= k <= n0 <= nums[i] <= 10^5
解法思路
定长滑动窗口——本题的窗口不是长度 k,而是一个长度为 2k+1 的窗口(以下标 i 为中心,左界 i-k,右界 i+k)。关键在「把新题往模板上靠」:把窗口长度识别成 2k+1,就回归到熟悉的定长滑窗套路。
边界处理:只有当 k <= i <= n-k-1 时,长度为 2k+1 的子数组才能完整地落在数组中。因此:
- 初始化答案数组全为
-1,只有能形成完整窗口的位置才需要计算; - 若
2k+1 > n,任意下标都无法形成完整窗口,直接返回全-1; - 若
k == 0,窗口就是元素本身,直接返回原数组。
掩盖「窗口右移对应中心回填」这一细节:落在完整窗口内的下标与窗口右端点不同——右端点进一位,窗口中心才前进一位。所以用右端点指针遍历时,当前窗口 [i-2k, i] 的中心是 i-k,平均值要回填到 avgs[i-k]。
沿用 入-更新-出 三步(同时维护窗口和,避免重复求和):
- 入:右端点
nums[i]进入窗口,s += nums[i];窗口不足2k+1时继续。 - 更新:窗口长度为
2k+1,记录avgs[i-k] = s // (2k+1)。 - 出:左端点
nums[i-2k]离开窗口,s -= nums[i-2k]。
逐步举例(nums = [7,4,3,9,1,8,5,2,6], k = 3,窗口长 2k+1=7)。中心 i 只能在 [3, 5] 形成完整窗口,故首尾 3 个下标返回 -1:
- 先统计前 7 个元素
[7,4,3,9,1,8,5]之和s = 37,其中心是9(下标3),回填avgs[3] = 37//7 = 5。 - 右移一步:出
7、入2→[4,3,9,1,8,5,2],s = 32,中心1(下标4),avgs[4] = 32//7 = 4。 - 再右移:出
4、入6→[3,9,1,8,5,2,6],s = 34,中心8(下标5),avgs[5] = 34//7 = 4。
最终 avgs = [-1,-1,-1,5,4,4,-1,-1,-1],与预期一致。注意窗口每右移一位,中心只前进一位,故回填位置是 i-k。
思路与写法参考灵茶山艾府《【模板】定长滑动窗口》(入-更新-出套路)及 2090 对应题解。
复杂度分析
- 时间复杂度:O(n),每个元素进/出窗口各一次。
- 空间复杂度:O(n),用于返回答案数组。
代码实现
class Solution: def getAverages(self, nums: list[int], k: int) -> list[int]: n = len(nums) ans = [-1] * n if k == 0: return nums if n < 2 * k + 1: return ans window = 2 * k + 1 cur = sum(nums[:window]) ans[k] = cur // window for i in range(k + 1, n - k): cur += nums[i + k] - nums[i - k - 1] ans[i] = cur // window return ansimport unittest
class TestGetAverages(unittest.TestCase): def setUp(self): self.solution = Solution()
def test_example1(self): self.assertEqual( self.solution.getAverages([7, 4, 3, 9, 1, 8, 5, 2, 6], 3), [-1, -1, -1, 5, 4, 4, -1, -1, -1], )
def test_example2(self): self.assertEqual(self.solution.getAverages([100000], 0), [100000])
def test_small_array(self): self.assertEqual(self.solution.getAverages([1, 2], 1), [-1, -1])
if __name__ == "__main__": unittest.main() 2090. 半径为 k 的子数组平均值
https://h1s97x.github.io/posts/coding/coding-2090-k-radius/