0

Question:

You are given an integer array nums consisting of n elements, and an integer k.Find a contiguous subarray whose length is equal to k that has the maximum average value and return this value. Test Case- nums = [1,12,-5,-6,50,3], k = 4

The answer I am getting is 12.00000 instead of 12.75000. This happens every time there a max value that is not completely divisible by k.

Can someone tell me why?

Here's my solution:

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        int n = nums.length;
        double s = 0;
        double max = Integer.MIN_VALUE;

        if (n == 1){
            max = Double.valueOf(nums[0]);
        } 
        else {
            for (int i = 0; i <= n-k; i++){
                for(int j = i; j < i+k-1; j++){
                    s += nums[j]; 
                    max = Math.max(max, s);
                }
            }
        }
        return max/k;
    }
}

4 Answers 4

1

Fixed the solution

Here are the issues with the provided solution:

  1. The inner loop's iteration condition is incorrect. It should be j <= i + k - 1 instead of j < i + k - 1. The original condition causes the loop to terminate one index before the desired subarray length.

  2. The accumulation of the sum (s) is not reset correctly within each iteration of the outer loop. Currently, the sum keeps accumulating from the previous subarray, leading to incorrect results. The s variable should be reset to 0 at the beginning of each outer loop iteration.

  3. The maximum value (max) is not being calculated correctly. The current implementation compares the cumulative sum (s) with the maximum value (max) within the inner loop, which results in incorrect values. Instead, the maximum value should be updated after each subarray's sum is calculated, not within the inner loop.

Here's the corrected code:

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        int n = nums.length;
        double max = Integer.MIN_VALUE;

        if (n == 1) {
            max = Double.valueOf(nums[0]);
        } else {
            for (int i = 0; i <= n - k; i++) {
                double s = 0;
                for (int j = i; j <= i + k - 1; j++) {
                    s += nums[j];
                }
                max = Math.max(max, s);
            }
        }
        return max / k;
    }
}

With these corrections, the solution should correctly calculate and return the maximum average value.

Optimization

Due to the time complexity issue of the previous code, which was O(n^2) and resulted in exceeding the time limit, it was necessary to optimize it using the sliding window technique to achieve a time complexity of O(n). Here's the optimized code:

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        int n = nums.length;
        int maxSubSum = Integer.MIN_VALUE;
        int currentSubSum = 0;
        int l = 0;
        int r = 0;
        while (l + k - 1 < n) {
            while (r - l + 1 <= k) {
                currentSubSum += nums[r];
                r++;
            }
            maxSubSum = Math.max(maxSubSum, currentSubSum);
            currentSubSum -= nums[l];
            l++;
        }
        return (double) maxSubSum / k;
    }
}

The explanation of the optimized solution

Here's the explanation of the optimized solution with a time complexity of O(n):

The optimized solution uses a sliding window technique to find the maximum subarray sum. Here's how it works:

  1. Initialize the variables maxSubSum and currentSubSum to track the maximum subarray sum and the sum of the current subarray, respectively. Set maxSubSum to Integer.MIN_VALUE to ensure correct initialization.

  2. Initialize two pointers, l and r, representing the left and right boundaries of the subarray.

  3. While the right boundary r is within the array bounds and while the subarray length (r - l + 1) is less than or equal to k, perform the following steps:

    • Add the element at the right boundary (nums[r]) to the currentSubSum.
    • Increment the right boundary r.
  4. Once the subarray length exceeds k, update the maxSubSum by comparing it with the currentSubSum. Take the maximum of the two values.

  5. Subtract the element at the left boundary (nums[l]) from the currentSubSum and increment the left boundary l.

  6. Repeat steps 3 to 5 until the left boundary l reaches the end of the array.

  7. Finally, return the maximum subarray sum (maxSubSum) divided by k as the maximum average value.

This optimized solution avoids unnecessary recalculations by using a sliding window approach, reducing the time complexity to O(n).

Sign up to request clarification or add additional context in comments.

6 Comments

Just wanted to ask, how is your optimized code has linear time, whereas initial code has quadratic time, as you said?
@Zero In the "original code," there are two nested loops. The outer loop runs for (n - k + 1) iterations, and the inner loop runs for k iterations. As a result, the total number of comparisons is (n - k + 1) * k, which leads to a time complexity of O(n^2).
@Zero In the "optimized code," the sliding window technique is used to eliminate the inner loop. It maintains two pointers, l and r, representing the left and right boundaries of the current window. In each iteration, the window moves by incrementing r and decrementing l. The current subarray sum is updated by subtracting the value of the left element of the window and adding the value of the right element. This approach only requires traversing the array once, resulting in a time complexity of O(n).
I know the sliding window technique @jesse, and as you explained above the original code, indeed has two nested loops, but so does your optimized code, just changed from while to for. You explained upper code runs for (n-k+1)*k which is the same for optimized code also. It is just that k is taken constant, so it is not counted in time complexity and it is therefore calculated as O(n) (in both cases, as there's only one n). Sliding Window is somewhat confusing at the start, and sometimes even instructors also confuse it but do the calculations mate.
@Zero In this problem, k is not constant. There are constraints on k: n == nums.length, 1 <= k <= n <= 10^5. Let's consider a case where n = 10^5 and k = n / 2. In this scenario, the original code runs for (n/2+1)*n/2, which is almost equal to n^2. Therefore, in terms of Big O notation, we would refer to the time complexity as O(n^2), as we always consider the worst case scenario."
|
0

You need move

max = Math.max(max, s);

out of the inner loop, so that it takes the max sum of the entire window of k numbers. Putting it inside will fail if windows have any trailing negative values.

Also, reset s to 0 with each window check.

Final code will be

class Solution {
    public double findMaxAverage(int[] nums, int k) {
        int n = nums.length;
        double s = 0;
        double max = Integer.MIN_VALUE;

        if (n == 1){
            max = Double.valueOf(nums[0]);
        } else{
            for(int i = 0; i < n-k; i++){
                s = 0;
                for(int j = i; j < i+k; j++){
                    s += nums[j]; 
                }
                max = Math.max(max, s);
            }
        }

        return max/k;
    }
}

This code is passing LeetCode testcases.

Comments

0

I have tested both Jesse's sliding window solution and a nested for loop solution on Leetcode. My solutions are a bit different but both work. There is a huge difference in run time between the solutions.

Nested for loops:

public static double findMaxAverage(int[] nums, int k) {                   
                                                
    int n = nums.length;                                                  
    double max = Integer.MIN_VALUE;                                       
    double avg = 0;                                                       
    for (int i = 0; i < n; i++) {                                         
        if ((i + k) < n) {                                                
            double sum = 0;                                               
            for (int j = i; j < k + i; j++) {                                                    
                sum += nums[j];                                           
            }                                                                                   
            if (sum > max) {                                              
                max = sum;                                                                  
            }                                                             
        }                                                                 
    }                                                                     
    return max / k;                                                       
}

Runtime 5ms.

Sliding window:

public static double findMaxAverageSliding(int[] nums, int k) {          
    printArray(nums);                                                   
    int n = nums.length;                                                
    double max = Integer.MIN_VALUE;                                     
    double sum = 0;                                                     
                                                                        
    int left = 0;                                                       
    int right = 0;                                                      
                                                                        
    while (left + k <= n) {                                             
        while (right - left < k) {                                      
            sum += nums[right];                                         
            right++;                                                    
        }                                                               
        max = Math.max(max, sum);                                       
        sum -= nums[left];                                              
        left++;                                                         
    }                                                                   
                                                                        
    return max / k;                                                     
}                                                                       

Runtime 0ms.

Looks like sliding window is the superior solution.

Comments

-2
def max_avg_subarray(nums, k):
    max_avg = 0
    start = k
    base = 0
    for i in range(start, len(nums)+1):
        sum_sub = sum(nums[base: i])
        avg = sum_sub/k
        max_avg = max(max_avg, avg)
        base +=1
    return max_avg
nums =  [1,12,-5,-6,50,3]
k = 4
print (max_avg_subarray(nums, k))

2 Comments

solutions: find the possible continuous subarray with length of k
Question is a debugging question using Java. This is not even Java.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.