1、题目描述
https://leetcode-cn.com/problems/maximum-average-subarray-i/
给定 n
个整数,找出平均数最大且长度为 k
的连续子数组,并输出该最大平均数。
输入:[1,12,-5,-6,50,3], k = 4
输出:12.75
解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75
2、代码详解
法一:前缀和
先遍历一次,求数组每个位置的 preSum,然后再遍历一次,求长度为 k 的每个区间的最大和。最终除以 k 得到最大平均数。
利用 preSum 数组,
- 可以在 O(1) 的时间内快速求出 nums 任意区间 [i, j] (两端都包含) 的各元素之和。
- sum(i, j) = preSum[i + 1] - preSum[j]
class Solution(object):
def findMaxAverage(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: float
"""
n = len(nums)
preSum = [0] * (n+1)
for i in range(n):
preSum[i+1] = preSum[i] + nums[i]
largest = float('-inf')
for i in range(k-1, n):
# 前缀和 sum(i, j) = preSum[i + 1] - preSum[j]
largest = max(largest, preSum[i+1] - preSum[i+1-k])
return largest/float(k)
nums = [1,12,-5,-6,50,3]
k = 4
s = Solution()
print(s.findMaxAverage(nums, k))
法二:滑动窗口
抽象成长度固定为 k 的滑动窗口。
- 当每次窗口右移的时候,需要把右边的新位置 加到 窗口中的 和 中,把左边被移除的位置从窗口的 和 中 减掉。
- 这样窗口里面所有元素的 和 是准确的,我们求出最大的和,最终除以 k 得到最大平均数。这个方法只用遍历一次数组。
需要注意的是,需要根据 i 的位置,计算滑动窗口是否开始、是否要移除最左边元素:
- 当 i >= k - 1 时,最左边第一个滑动窗口内的元素刚好 k 个,开始计算滑动窗口的最大和。
- 当 i >= k 时,为了固定窗口的元素是 k 个,每次移动时需要将 i - k 位置的元素移除。
class Solution(object):
def findMaxAverage(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: float
"""
sums = 0
largest = float('-inf')
for i, num in enumerate(nums):
sums += num
if i >= k:
sums -= nums[i - k]
if i >= k - 1:
largest = max(sums, largest)
return largest / float(k)