LearnAbout

Sliding Window

On this page
Quick reference
Fixed-size windowO(n)
Variable-size windowO(n) amortized
Recomputing every subarray from scratch (for comparison)O(n²) or worse
The Idea

A window is a continuous part of the array. It has a start edge and an end edge. Everything between them is in the window. Think about a question such as "what is the best sum of any 5 consecutive elements". The brute-force method checks each possible part from the start. For each start point, it moves forward and adds each element in that part again. This method computes the same elements many times. Sliding window keeps one window and moves it. The end edge moves forward to add a new element. The start edge moves forward to drop an old element. A running total gets one small update instead of a full rebuild.

This method has two shapes. A fixed-size window always covers exactly k elements. It moves one step at a time. It gains one element on the right and loses exactly one element on the left. A variable-size window grows and becomes smaller based on a condition. Expand the right edge while the window is valid. When the window stops being valid, make it smaller from the left until it is valid again.

This is the improvement from sliding window. Do not compute each subarray total from the start (O(n) work for each subarray, and O(n²) or worse in total). Instead, update a running total by one element of work when the window moves.
Build It
Window shapes
// Fixed-size window of width k
windowSum = sum of the first k elements
for right from k to length - 1:
    windowSum += arr[right]           // the element that enters on the right
    windowSum -= arr[right - k]        // the element that leaves on the left
    ... use windowSum ...

// Variable-size window
left = 0
for right from 0 to length - 1:
    ... add arr[right] to the running state of the window ...
    while the window is invalid:
        ... remove arr[left] from the running state of the window ...
        left += 1
    ... the window [left, right] is now valid. Use it. ...
fixed-size window — maintain a running aggregate
function maxFixedWindowSum(arr, k):
    windowSum = 0
    for i from 0 to k - 1:
        windowSum += arr[i]           // build the first window directly
    best = windowSum
    for right from k to length(arr) - 1:
        windowSum += arr[right]         // the element that enters
        windowSum -= arr[right - k]      // the element that leaves
        best = max(best, windowSum)
    return best
variable-size window — grow, then shrink until valid again
function smallestWindowAtLeastTarget(arr, target):
    left = 0
    windowSum = 0
    best = infinity
    for right from 0 to length(arr) - 1:
        windowSum += arr[right]                 // grow: always add the new right edge
        while windowSum >= target:                // shrink while the window is still valid
            best = min(best, right - left + 1)
            windowSum -= arr[left]
            left += 1
    return best if best != infinity else 0
The right edge moves only forward. The left edge also moves only forward. Neither edge goes backward. This keeps the method a single pass instead of a nested re-scan.
Know It

The shape with a while-loop inside a for-loop looks like O(n²). But it never examines an element that it has already dropped. Each index enters the window exactly one time (when right reaches it). Each index leaves exactly one time (when left passes it). The total movement across both edges is a maximum of 2n steps.

OperationTimeSpaceWhy
Fixed-size windowO(n)O(1) extra (plus the state that the window tracks)One slide for each position. One element enters and one element leaves. Both are O(1). There are n slides in total.
Variable-size windowO(n) amortizedO(1) extra (plus the tracked state)Remember "amortized" from Arrays & Strings Fundamentals. The inner while-loop looks like it can repeat. But left moves only forward and can advance a maximum of n times in the full run. So the two nested loops together are still O(n), not O(n²).
Recomputing every subarray from scratch (for comparison)O(n²) or worseO(1)A new sum of a part of up to n elements, for each of up to n start points, is the cost. Sliding window exists to prevent this cost.
Break It

Window larger than the array

k is more than the length of the array

A fixed-size window of width k assumes that at least k elements exist. If you build "the first window" with a sum of arr[0..k-1] and do not check the length first, you read past the end of the array. Always check k against the length of the array before you build the first window.

Recomputing the aggregate instead of updating it

each slide re-sums the full window instead of a change by one element

It is easy to write code that looks like sliding window (a loop with a window of size k) but re-sums all k elements at each position. The correct method adds the element that enters and subtracts the element that leaves. The wrong method changes an O(n) sliding window into an O(n·k) brute force. The structure is the same, but there is no speed benefit.

Off-by-one on window boundary indices

you calculate the width of the window or the index of the element that leaves

The element that leaves a fixed-size window at position right is at right - k, not right - k + 1 or right - k - 1. The width of a window is right - left + 1, not right - left. Both are easy to get wrong. Both give a wrong answer with no error, not a crash.

A shrink condition that never triggers

the validity check of the while-loop is always true (or always false)

If the shrink condition can never become false, left never advances and the window only grows. This changes a variable-size window into a full O(n) rescan at each step (O(n²) in total) instead of an amortized O(n) sweep. Trace the condition against a small example by hand before you trust it.

Use It
Maximum Subarray
Extend the running-aggregate idea from Build It. Keep a running sum. Reset it to zero (start a new window) when it becomes negative, because a negative running sum can only reduce everything after it. Keep the best sum that you have seen.
Medium
Maximum Average Subarray I
This is the standard fixed-size window. Compute the sum of the first window directly. Then slide one step at a time. Add the element that enters and subtract the element that leaves. Never re-sum the full window.
Easy
Longest Substring Without Repeating Characters
Use a variable-size window. Grow the right edge while each character inside stays unique. Track the characters with an array indexed by character code (the same addressable-slots idea from Arrays & Strings Fundamentals). When a repeat appears, make the window smaller from the left until the repeat is gone.
Medium
Minimum Size Subarray Sum
Use almost the exact smallestWindowAtLeastTarget shape from Build It. Grow the right edge and add to a running sum. When the sum reaches the target, make the window smaller from the left as far as possible while it still reaches the target. Keep the smallest width that you have seen.
Medium
Longest Repeating Character Replacement
Track a frequency count (an array indexed by letter) for the characters in the window now. Also track the count of the most frequent letter inside the window. The window is valid while (window size − that peak count) is a maximum of k replacements. Make the window smaller from the left when this is not true.
Medium
Permutation in String
Use a fixed-size window with the length of the pattern. Keep a running frequency count (an array indexed by letter) of the letters in the window. Compare this count against the frequency count of the pattern at each slide. This is one array comparison for each shift, not a new sort or rebuild.
Medium
Find All Anagrams in a String
Use the same fixed-size frequency-matching window as Permutation in String. Do not stop at the first match. Slide through the full string and record each start index where the letter counts of the window match the pattern.
Medium
Fruit Into Baskets
Use a variable-size window that allows a maximum of two different fruit types. Always grow the right edge. Track a count of each type in the window. Make the window smaller from the left when a third type would need to enter.
Medium
Contains Duplicate II
Use a fixed-size window of width k. Keep a fast lookup of which values are in the window now (you will meet the fast structure made for this in the next topic). If the value that is about to enter is already in the lookup, you have the answer. If not, remove the oldest value from the lookup as it leaves the window.
Easy
Maximum Number of Vowels in a Substring of Given Length
Use a standard fixed window again. Count the vowels in the first window of size k directly. Then slide. Add one if the character that enters is a vowel. Subtract one if the character that leaves was a vowel. Keep the maximum that you have seen.
Medium