Maximum Average Subarray II

Updated on 06 June, 2025
Maximum Average Subarray II header image

Problem Statement

Given an integer array nums with n number of elements and an integer k, the task is to identify a contiguous subarray of length at least k that has the highest average value. The solution should return the maximum average value of any such subarray. Answers within a small calculation error (less than (10^{-5})) are considered acceptable. This problem not only tests basic array manipulations but also challenges one's understanding of subarray calculation and optimization criteria for handling larger datasets efficiently.

Examples

Example 1

Input:

nums = [1,12,-5,-6,50,3], k = 4

Output:

12.75000
**Explanation:**- When the length is 4, averages are [0.5, 12.75, 10.5] and the maximum average is 12.75
- When the length is 5, averages are [10.4, 10.8] and the maximum average is 10.8
- When the length is 6, averages are [9.16667] and the maximum average is 9.16667
The maximum average is when we choose a subarray of length 4 (i.e., the sub array [12, -5, -6, 50]) which has the max average 12.75, so we return 12.75
Note that we do not consider the subarrays of length < 4.

Example 2

Input:

nums = [5], k = 1

Output:

5.00000

Constraints

  • n == nums.length
  • 1 <= k <= n <= 104
  • -104 <= nums[i] <= 104

Approach and Intuition

To solve this problem effectively, we have to focus on a few key points:

  • Understand the requirements rigorously: You need to find a subarray of at least length k that has the largest average. A subarray is defined as a contiguous block of elements within the parent array.

  • Sliding Window Technique: One optimal way to tackle this is to use the sliding window technique combined with maintaining running sums of elements within the window:

  1. Start with a window (subarray) of size k and compute its sum.
  2. Slide this window across the array to the end. For each move, adjust the sum by subtracting the element that is left behind and adding the new element that comes into the window.
  3. Record the maximal average by comparing the average of the current window with the previously recorded maximum.
  4. This procedure ensures that every subarray of size >= k is considered without the need for redundant calculations, significantly reducing time complexity.
  • Efficiency: Since this approach incrementally adjusts the window sum (sliding the window), it operates in (O(n)) time where n is the number of elements in nums. This is crucial for large arrays.

  • Returning the Result: After sliding through possible windows, the maximum recorded average is returned. Given the constraints, this approach will handle even the upper boundaries efficiently.

  • Edge Case Consideration: For cases where n is equal to k, the entire array is the only subarray that meets the criteria. Ensure this case is handled by default in the sliding mechanism.

The clear challenge lies in managing the window sum efficiently and ensuring that the procedure works seamlessly from k up to n elements of the array, capturing every potential subarray scenario.

Solutions

  • Java
java
public class Solution {
    public double maximumAverageSubarray(int[] values, int subarraySize) {
        double highestAverage = Integer.MIN_VALUE;
        double lowestAverage = Integer.MAX_VALUE;
        for (int value : values) {
            highestAverage = Math.max(highestAverage, value);
            lowestAverage = Math.min(lowestAverage, value);
        }
        double lastMid = highestAverage, precision = Integer.MAX_VALUE;
        while (precision > 0.00001) {
            double midPoint = (highestAverage + lowestAverage) * 0.5;
            if (isValidAverage(values, midPoint, subarraySize))
                lowestAverage = midPoint;
            else
                highestAverage = midPoint;
            precision = Math.abs(lastMid - midPoint);
            lastMid = midPoint;
        }
        return lowestAverage;
    }

    public boolean isValidAverage(int[] data, double currentMid, int size) {
        double currentSum = 0, initialSum = 0, minInitialSum = 0;
        for (int i = 0; i < size; i++)
            currentSum += data[i] - currentMid;
        if (currentSum >= 0)
            return true;
        for (int i = size; i < data.length; i++) {
            currentSum += data[i] - currentMid;
            initialSum += data[i - size] - currentMid;
            minInitialSum = Math.min(initialSum, minInitialSum);
            if (currentSum >= minInitialSum)
                return true;
        }
        return false;
    }
}

The code provided solves the problem of finding the maximum average of any subarray of a given size within an array using Java. Here's a step-by-step breakdown of the algorithm implemented:

  • Initialize Variables: Start by determining the possible minimum (lowestAverage) and maximum (highestAverage) values for the average of subarrays. This is set based on the minimum and maximum elements in the input array values.

  • Binary Search Setup: Use a binary search approach between lowestAverage and highestAverage to find the maximum possible average to a specified precision. The precision check ensures that the loop stops when the difference between successive values (lastMid and midPoint) is extremely small (0.00001), indicating convergence.

  • Iterative Search and Convergence: In each iteration, calculate the midpoint of current high and low averages. Use the isValidAverage() helper function to decide whether to adjust the lowestAverage or highestAverage based on the feasibility of the midpoint average over subarrays.

  • Subarray Validation via Prefix Sums: The isValidAverage() function employs prefix sums to efficiently check if there's at least one subarray with the specified size size which has an average at least as good as currentMid. By adjusting for currentMid directly in the sum comparison, rather than computing actual averages, it accelerates the checking process.

  • Return the Result: Once the binary search completes, lowestAverage will contain the largest valid average found to the nearest precision defined.

This solution effectively handles the problem by balancing between correctness (through an exhaustive search using isValidAverage) and efficiency (using binary search to narrow down the possible results swiftly). It leverages mathematical properties (like prefix sums and binary search principles) to compute the result with both high performance and accuracy.

Comments

No comments yet.