DevLift
Back to Blog

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.

Admin
January 12, 20264 min read77 views

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
Rendering diagram...

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.

💡
Fixed-size sliding window works whenever your window has a fixed number of elements and you're tracking a value that updates incrementally (sum, product, frequency count).

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 array

Notice 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: 6

This 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.

⚠️
Most people try to track which specific zeros they've "used". You don't need to. Just count zeros in the window and shrink left when the count exceeds k.
// 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)
This problem bridges fixed and variable sliding window. The window size varies, but the zero-count constraint is fixed at k. When you recognize a "budget" constraint like this, the sliding window pattern should immediately come to mind.

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=6

Complexity Cheat Sheet

ProblemApproachTimeSpace
Max Sum Subarray of Size KBrute ForceO(n·k)O(1)
Max Sum Subarray of Size KSliding WindowO(n)O(1)
Average of Subarrays of Size KSliding WindowO(n)O(n)
Max Consecutive Ones IIISliding WindowO(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!

Related Articles

A monotonic stack maintains elements in order and pops when that order breaks — finding the next greater element for every popped value in O(n) total.
AdminAugust 3, 20265 min read
Union Find: The Structure That Only Answers "Same Group?"
Union Find trades every graph question except one for speed, and measured tree heights show exactly what path compression and union by rank each buy you — with tested solutions to Redundant Connection, Number of Connected Components, and Accounts Merge.
AdminAugust 6, 20268 min read
Do [1,4] and [4,5] Overlap? Answer That First
LeetCode 56 merges [1,4] and [4,5]; LeetCode 435 says they do not overlap at all. Closed versus half-open ends is the one real decision in interval problems, and most interval bugs come from never making it.
AdminAugust 11, 20268 min read