Brute force nested loops → Sliding Window. Learn why we slide instead of re-sum.
Problem Statement
An integer array nums of n elements and an integer k. Find a contiguous subarray whose length equals k that has the maximum average value. Return that average.
Example 1
Input: nums = [1, 12, -5, -6, 50, 3], k = 4
Output: 12.75000
Explanation: Max average = (12 − 5 − 6 + 50) / 4 = 51 / 4 = 12.75
Example 2
Input: nums = [5], k = 1
Output: 5.00000
Answers within 10−5 of the true answer are accepted.
What Are We Looking For? 🧠
We want the window of k consecutive numbers that has the highest average. Average = sum / k. Since k is fixed, maximising the average is the same as maximising the sum. So the problem reduces to: find the contiguous subarray of length exactly k with the biggest sum.
nums = [1, 12, −5, −6, 50, 3] | k = 4 — all possible windows:
▶ Window 1 (idx 0–3): 1+12−5−6 = 2 → avg = 0.5
▶ Window 2 (idx 1–4): 12−5−6+50 = 51 → avg = 12.75 ✅ BEST
▶ Window 3 (idx 2–5): −5−6+50+3 = 42 → avg = 10.5
Approaches at a Glance
🐌 Brute Force (Nested Loops)
Outer loop picks each window start. Inner loop sums the k elements. Check all windows.
⚡ Sliding Window (Optimal)
Reuse the previous window sum. Subtract one element, add one element. One pass only.
Approach 1 — Brute Force (Nested Loops)
The straightforward idea: for every valid starting index i (from 0 to n−k), sum the next k elements (indices i to i+k−1), compute the average, and track the maximum.
- Initialise
maxAvgto the average of the very first window (so negative numbers don’t break the comparison). - Outer loop:
ifrom0ton−kinclusive — each position is a window start. - Inner loop:
jfromitoi+k−1— sum the window’s k elements. - Compute average =
windowSum / k. UpdatemaxAvgif this is bigger. - Return
maxAvgafter all windows are checked.
🔍 Dry Run — Brute Force
Input: nums = [1, 12, −5, −6, 50, 3], k = 4
n = 6, so outer loop runs i = 0, 1, 2 (i ≤ n−k = 2)
| i (start) | j range | Elements summed | windowSum | avg | maxAvg |
|---|---|---|---|---|---|
| 0 | 0 → 3 | 1, 12, −5, −6 | 2 | 0.5 | 0.5 (init) |
| 1 | 1 → 4 | 12, −5, −6, 50 | 51 | 12.75 | 12.75 ↑ |
| 2 | 2 → 5 | −5, −6, 50, 3 | 42 | 10.5 | 12.75 (no change) |
Problem: For each of the 3 windows, we re-summed all 4 elements from scratch. That’s 3 × 4 = 12 operations for this tiny input. With n=100,000 and k=50,000 this becomes 50,000 × 50,001 ≈ 2.5 billion operations. Way too slow!
[1, 12, −5, −6] to [12, −5, −6, 50], we re-added 12, −5, and −6 even though they were already in the previous sum. We’re doing unnecessary repeated work. This is exactly what Sliding Window eliminates.
Approach 2 — Sliding Window (Optimal) ⚡
The Key Intuition
Look at what changes between two consecutive windows of size k:
New sum = Old sum − nums[windowStart] + nums[windowEnd]
= 2 − 1 + 50 = 51 — no inner loop needed!
How the Algorithm Works
- Expand
windowEndone step at a time, addingnums[windowEnd]towindowSum. - When the window size reaches exactly k (
windowEnd − windowStart + 1 == k): - Update
maxSumifwindowSumis bigger. - Shrink the window from the left: subtract
nums[windowStart]fromwindowSum, then advancewindowStart++. - After the loop, return
maxSum / k.
🔍 Dry Run — Sliding Window
Input: nums = [1, 12, −5, −6, 50, 3], k = 4
Initial state: windowStart = 0, windowSum = 0, maxSum = 0
maxSum = max(0, 2) = 2
windowSum −= nums[0]=1 → windowSum = 1 • windowStart → 1
maxSum = max(2, 51) = 51 ↑ NEW BEST!
windowSum −= nums[1]=12 → windowSum = 39 • windowStart → 2
maxSum = max(51, 42) = 51 (no change)
windowSum −= nums[2]=−5 → windowSum = 47 • windowStart → 3 (loop ends)
Efficiency: 6 iterations total (n=6). No inner loop. Every element touched exactly once.
Time & Space Complexity
| Approach | Time | Space | Note |
|---|---|---|---|
| Brute Force (Nested Loops) | O(n × k) | O(1) | Re-sums k elements for every window start |
| Sliding Window | O(n) | O(1) | Single pass; each element added and removed once |