Sliding Window
Quick reference
| Fixed-size window | O(n) |
| Variable-size window | O(n) amortized |
| Recomputing every subarray from scratch (for comparison) | O(nΒ²) or worse |
A window is just a contiguous stretch of the array β a start edge and an end edge, with everything between them "in the window." The brute-force way to answer a question like "what's the best sum of any 5 consecutive elements" is to check every possible stretch from scratch: for each starting point, walk forward and re-add every element in that stretch. That recomputes the same elements over and over. Sliding window instead keeps one window alive and slides it β as the end edge moves forward to include a new element, the start edge moves forward to drop an old one, and a running total is updated incrementally instead of rebuilt.
There are two shapes this takes. A fixed-size window always covers exactly k elements β it slides one step at a time, gaining one element on the right and losing exactly one on the left. A variable-size window grows and shrinks based on a condition: keep expanding the right edge while things are valid, and the moment they stop being valid, shrink from the left until they're valid again.
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] // element entering on the right
windowSum -= arr[right - k] // element leaving on the left
... use windowSum ...
// Variable-size window
left = 0
for right from 0 to length - 1:
... add arr[right] to the window's running state ...
while window is invalid:
... remove arr[left] from the window's running state ...
left += 1
... 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 sliding in
windowSum -= arr[right - k] // the element sliding out
best = max(best, windowSum)
return bestvariable-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 still valid
best = min(best, right - left + 1)
windowSum -= arr[left]
left += 1
return best if best != infinity else 0The nested while-inside-for shape looks like it could be O(nΒ²), but it never re-examines an element it has already dropped. Every index enters the window exactly once (when right reaches it) and leaves exactly once (when left passes it) β total movement across both edges is at most 2n steps.
| Operation | Time | Space | Why |
|---|---|---|---|
| Fixed-size window | O(n) | O(1) extra (plus whatever the window's tracked state needs) | One slide per position: one element added, one removed, both O(1) β n slides total. |
| Variable-size window | O(n) amortized | O(1) extra (plus tracked state) | Recall "amortized" from Arrays & Strings Fundamentals: the inner while-loop looks like it could repeat, but left only ever moves forward and can advance at most n times total across the entire run β so the two nested loops together still add up to O(n), not O(nΒ²). |
| Recomputing every subarray from scratch (for comparison) | O(nΒ²) or worse | O(1) | Re-summing a stretch of up to n elements for each of up to n starting points is the cost sliding window exists to avoid. |
Window larger than the array
A fixed-size window of width k assumes at least k elements exist. Building "the first window" by summing arr[0..k-1] without checking length first reads past the end of the array β always validate k against the array's length before the first window is built.
Recomputing the aggregate instead of updating it
It's easy to write code that looks like sliding window (a loop with a window of size k) but re-sums all k elements at every position instead of adding the entering element and subtracting the leaving one. That silently turns an O(n) sliding window into an O(nΒ·k) brute force β same structure, none of the speedup.
Off-by-one on window boundary indices
The element leaving a fixed-size window at position right is at right - k, not right - k + 1 or right - k - 1 β and a window's width is right - left + 1, not right - left. Both are easy to get backward, and both fail silently (wrong answer, not a crash) rather than loudly.
A shrink condition that never triggers
If the shrink condition can never become false, left never advances and the window only grows β turning a variable-size window into a full O(n) rescan on every step (O(nΒ²) overall) instead of an amortized O(n) sweep. Trace the condition against a small example by hand before trusting it.
Sign in to mark problems done β progress syncs across devices.