LeetCode643. 子数组最大平均数 I(前缀和、滑动窗口)

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]

LeetCode643. 子数组最大平均数 I(前缀和、滑动窗口)_第1张图片

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)

https://leetcode-cn.com/problems/maximum-average-subarray-i/solution/jing-dian-ti-mu-de-jing-dian-zuo-fa-pres-ze08/

你可能感兴趣的:(Array,前缀和,滑动窗口)