628 字
3 分钟
643. 子数组最大平均数 I
643. 子数组最大平均数 I
题目描述
给你一个由 n 个整数组成的数组 nums 和一个整数 k。
请你找出长度为 k 的连续子数组的最大平均数,并返回该最大值。
示例 1:
输入:nums = [1,12,-5,-6,50,3], k = 4输出:12.75解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75示例 2:
输入:nums = [5], k = 1输出:5.0提示:
n == nums.length1 <= k <= n <= 10^5-10^4 <= nums[i] <= 10^4
解法思路
定长滑动窗口。长度为 k 的子数组数量是 O(n) 个,但直接枚举每个子数组再求和需要 O(n·k)。由于窗口向右滑动时,离开窗口的只有最左一个元素、进入窗口的只有最右一个元素,中间 k-2 个元素不变,所以可以 O(1) 更新窗口和。
沿用定长滑窗的 入-更新-出 三步套路:
- 入:右端点
i进入窗口,窗口和cur += nums[i];若i < k-1窗口长度不足 k,继续循环。 - 更新:此时窗口长度为 k,用当前窗口和更新最大和
ans。 - 出:左端点
i-k+1离开窗口,cur -= nums[i-k+1],为下一轮做准备。
最后用最大和除以 k 得到最大平均数。
逐步举例(nums = [1,12,-5,-6,50,3], k = 4):
- 先统计前
k-1=3个元素和:1+12-5 = 8。 i=3,-6入窗 → 窗口[1,12,-5,-6],和= 2,更新ans = 2;出nums[0]=1→ 窗口和= 1。i=4,50入窗 → 窗口[12,-5,-6,50],和= 51,更新ans = 51;出nums[1]=12→ 窗口和= 39。i=5,3入窗 → 窗口[-5,-6,50,3],和= 42,ans仍为 51;出nums[2]=-5→ 窗口和= 47。
最大和为 51,最大平均数 = 51/4 = 12.75,与预期一致。可见每步只需加一个新元素、减一个旧元素,中间元素不重复求和。
注意:本题 nums 中含负数,所以 ans 不能初始化为 0,而应初始化为 -inf(或直接初始化为第一个窗口的和),否则当所有 L 都小于 0 时会得到错误结果。
详细讲解见灵茶山艾府的《【模板】定长滑动窗口》与该定长滑窗套路题解。
复杂度分析
- 时间复杂度:O(n),其中 n 是数组长度。
- 空间复杂度:O(1)。
代码实现
class Solution: def findMaxAverage(self, nums: list[int], k: int) -> float: cur = sum(nums[:k]) ans = cur for i in range(k, len(nums)): cur += nums[i] - nums[i - k] if cur > ans: ans = cur return ans / kimport unittest
class TestFindMaxAverage(unittest.TestCase): def setUp(self): self.solution = Solution()
def test_example1(self): self.assertAlmostEqual( self.solution.findMaxAverage([1, 12, -5, -6, 50, 3], 4), 12.75 )
def test_example2(self): self.assertAlmostEqual(self.solution.findMaxAverage([5], 1), 5.0)
def test_negative(self): self.assertAlmostEqual(self.solution.findMaxAverage([-1, -2, -3], 2), -1.5)
if __name__ == "__main__": unittest.main() 643. 子数组最大平均数 I
https://h1s97x.github.io/posts/coding/coding-643-max-average/