Fixed-Size Sliding Window — Maximum Sum Subarray, Max Consecutive Ones
Stop re-summing from scratch — the fixed-size sliding window reduces O(n·k) nested loops to a single O(n) pass by adding one element and dropping one.
Fixed-Size Sliding Window — Maximum Sum Subarray, Max Consecutive Ones
There's a whole category of problems where the interviewer gives you an array and a number k, and asks you to find the max (or min) something across every contiguous subarray of size k. If you reach for a nested loop — outer loop picks the start, inner loop sums k elements — you're going to get O(n·k). That'll pass small inputs and fail everything else.
The fix is the fixed-size sliding window. It reduces the inner loop to a constant-time operation: instead of re-summing from scratch, you add one element on the right and drop one element on the left. One pass, O(n) total.
The Pattern
A sliding window of fixed size k moves through an array one step at a time. At each step:
- Add the new element entering from the right:
arr[right] - Remove the element falling off the left:
arr[right - k] - Update your running answer
The key mechanical insight: arr[right - k] is always the element that just exited the left edge of the window. You never need a second loop.
Problem 1: Maximum Sum Subarray of Size K
Given an array of integers and a number k, find the maximum sum of any contiguous subarray of size k.
arr = [2,1,5,1,3,2], k = 3
Output: 9 (subarray [5,1,3])Brute Force — O(n·k) Time, O(1) Space
Two loops: outer picks the window start, inner sums k elements.
// Input: arr = [2,1,5,1,3,2], k = 3
// Output: 9
const maxSumBrute = (arr, k) => {
let maxSum = -Infinity;
for (let start = 0; start <= arr.length - k; start++) {
let windowSum = 0;
for (let i = start; i < start + k; i++) {
windowSum += arr[i];
}
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
};
// Time: O(n*k) | Space: O(1)This works fine for small inputs. The interviewer is already thinking about what happens when n is a million and k is half a million.
Sliding Window — O(n) Time, O(1) Space
Seed the first window, then slide.
// Input: arr = [2,1,5,1,3,2], k = 3
// Output: 9
const maxSum = (arr, k) => {
// Seed: compute sum of first window
let windowSum = 0;
for (let i = 0; i < k; i++) {
windowSum += arr[i];
}
let maxSum = windowSum;
// Slide the window: add right element, drop left element
for (let right = k; right < arr.length; right++) {
windowSum += arr[right] - arr[right - k]; // +incoming, -outgoing
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
};
// Time: O(n) | Space: O(1)The arr[right - k] is the element that just left the window. At right = k, the window covers indices [1, k], so arr[right - k] = arr[0] falls off. Clean.
Problem 2: Average of All Subarrays of Size K
Same structure, different output. Instead of max sum, return an array of averages for every window of size k.
arr = [1,3,-1,-3,5,3,6,7], k = 3
Output: [1.0, -0.33, 0.33, 1.67, 4.67, 5.33]// Input: arr = [1,3,-1,-3,5,3,6,7], k = 3
// Output: [1.0, -0.33, 0.33, 1.67, 4.67, 5.33]
const findAverages = (arr, k) => {
const result = [];
let windowSum = 0;
for (let i = 0; i < arr.length; i++) {
windowSum += arr[i]; // Add incoming element
// Once window is full, record average and drop outgoing element
if (i >= k - 1) {
result.push(windowSum / k);
windowSum -= arr[i - k + 1]; // Drop leftmost element of current window
}
}
return result;
};
// Time: O(n) | Space: O(n) for result arrayNotice the slight index shift: arr[i - k + 1] is the leftmost element of the current window at index i. Either formulation works — this one builds the window incrementally rather than seeding upfront.
Problem 3: Max Consecutive Ones III
LeetCode 1004 — given a binary array nums and an integer k, return the maximum number of consecutive 1s if you can flip at most k zeros.
nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
Output: 6This is the interesting variation. The window isn't literally a fixed size, but the constraint is fixed: at most k zeros inside the window. When you exceed k zeros, shrink from the left until you're back within budget.
// Input: nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
// Output: 6
const longestOnes = (nums, k) => {
let left = 0;
let zeroCount = 0;
let maxLength = 0;
for (let right = 0; right < nums.length; right++) {
// Expand window: count zeros entering from the right
if (nums[right] === 0) {
zeroCount++;
}
// Shrink window from left when we've exceeded our zero budget
while (zeroCount > k) {
if (nums[left] === 0) {
zeroCount--;
}
left++;
}
// Window [left, right] has at most k zeros — update max
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
};
// Time: O(n) | Space: O(1)Let's trace through the example:
nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2
right=3: nums[3]=0, zeroCount=1 → window=[0..3], len=4
right=4: nums[4]=0, zeroCount=2 → window=[0..4], len=5
right=5: nums[5]=0, zeroCount=3 → exceeds k!
shrink: left=0→1, nums[0]=1, no change to zeroCount
shrink: left=1→2, nums[1]=1, no change
shrink: left=2→3, nums[2]=1, no change
shrink: left=3→4, nums[3]=0, zeroCount=2 ✓ → window=[4..5]
right=6..10: window grows to [4..9], len=6 → maxLength=6Complexity Cheat Sheet
| Problem | Approach | Time | Space |
|---|---|---|---|
| Max Sum Subarray of Size K | Brute Force | O(n·k) | O(1) |
| Max Sum Subarray of Size K | Sliding Window | O(n) | O(1) |
| Average of Subarrays of Size K | Sliding Window | O(n) | O(n) |
| Max Consecutive Ones III | Sliding Window | O(n) | O(1) |
Interview Tips
State the pattern before coding. Say: "This is a fixed-size sliding window. I'll seed the first window, then on each step add the new right element and subtract the outgoing left element." This one sentence demonstrates pattern recognition and sets up the interviewer's expectations — they'll be watching you implement what you just described.
The index for the outgoing element trips people up. If your window spans [right - k + 1, right], the outgoing element is arr[right - k]. If you're iterating with a separate left pointer, you drop arr[left] before left++. Both work — pick one and be consistent.
Max Consecutive Ones III often comes up in disguise. Any problem that asks "longest subarray with at most k bad elements" is this problem. You'll see it with at-most-k odd numbers, at-most-k characters changed, etc. The window mechanism is identical: count the bad elements, and shrink left when the count exceeds the budget.
Comments (0)
No comments yet. Be the first to share your thoughts!
