Before attempting this problem, you should be comfortable with:
We need to find a contiguous subarray of length at least k with the maximum average. The brute force approach checks every possible subarray by trying all starting positions and all valid ending positions.
For each starting index, we extend the subarray one element at a time, maintaining a running sum. Once the length reaches k or more, we compute the average and update our result if it is larger.
res to negative infinity.s from 0 to n - k:sum_val = 0.i from s to n - 1:nums[i] to sum_val.i - s + 1 >= k:res if larger.res.Where is the number of elements in the array
nums.
Instead of checking all subarrays, we can binary search on the answer. The key insight is that the maximum average lies between the minimum and maximum values in the array. For a candidate average mid, we can efficiently check if there exists a subarray of length at least k with average greater than or equal to mid.
To check this, we subtract mid from each element. Now we need to find a subarray of length at least k with non-negative sum. Using prefix sums and tracking the minimum prefix sum before the current window, we can do this in linear time.
min_val and max_val as the minimum and maximum of nums.0.00001:mid = (min_val + max_val) / 2.check(nums, mid, k) to see if a valid subarray exists.true, set min_val = mid (answer is at least mid).max_val = mid.check function:nums[i] - mid.min_sum as the minimum prefix sum seen at least k positions before.current_sum - min_sum >= 0 at any point, return true.min_val.class Solution:
def findMaxAverage(self, nums: List[int], k: int) -> float:
max_val = float('-inf')
min_val = float('inf')
for n in nums:
max_val = max(max_val, n)
min_val = min(min_val, n)
prev_mid = max_val
error = float('inf')
while error > 0.00001:
mid = (max_val + min_val) * 0.5
if self.check(nums, mid, k):
min_val = mid
else:
max_val = mid
error = abs(prev_mid - mid)
prev_mid = mid
return min_val
def check(self, nums: List[int], mid: float, k: int) -> bool:
sum_val = 0
prev = 0
min_sum = 0
for i in range(k):
sum_val += nums[i] - mid
if sum_val >= 0:
return True
for i in range(k, len(nums)):
sum_val += nums[i] - mid
prev += nums[i - k] - mid
min_sum = min(prev, min_sum)
if sum_val >= min_sum:
return True
return FalsefindMaxAverage().check() function dominates the time complexity, which is of for each invocation.Where is the number of elements in the array, and
rangeis the difference between the maximal and minimal values in the array, i.e.range = max_val - min_val, and finallyerroris the precision required in the problem.
The subarray must have length at least k. A common mistake is to check all subarrays without enforcing this constraint, or to only check subarrays of exactly length k and miss longer subarrays that could have a higher average.
Binary search on real numbers requires careful handling of precision. Setting the tolerance too tight can cause infinite loops, while setting it too loose yields inaccurate answers. The epsilon value of 0.00001 must be chosen to match the problem's precision requirements.
The check function determines if a subarray with average at least mid exists. The trick of subtracting mid from each element and finding a non-negative sum subarray is subtle. Errors in tracking prefix sums or the minimum prefix sum lead to false positives or negatives.
In the check function, you need the minimum prefix sum that ends at least k positions before the current index. Off-by-one errors in when to update min_sum versus when to use it cause the check to return incorrect results.
When the check returns true, it means a valid subarray exists with average at least mid, so the answer is at least mid and we should search higher. Reversing this logic inverts the binary search and produces wrong answers.