Theory · Sliding Window
DSA Roadmap Open Visualizer Back to intro

Algocraft · Theory

Sliding Window: turning O(n²) into O(n)

A huge class of problems ask something about every contiguous subarray or substring: the longest one, the largest sum, the maximum value. The brute-force instinct is to recompute the answer for every possible window, from scratch, every time. Sliding window replaces that with something far cheaper: as the window moves, you incrementally update your running answer instead of starting over. Both pointers — left and right — only ever move forward, never backward, and that single constraint is what keeps the whole thing linear.

01 · Foundation

The brute-force baseline, and the shortcut

Take "longest substring without repeating characters," or "maximum sum of any window of size k." The naive approach is to check every possible contiguous window: there are roughly n starting points and up to n possible lengths, and if computing "is this window valid?" or "what's its sum?" from scratch takes its own O(n) pass, you land at O(n²) or worse before you've written a single optimization.

Here's the shortcut. When a window slides one step to the right, almost nothing about its contents actually changes — exactly one element leaves (whatever sat at the old left edge) and exactly one element enters (whatever sits at the new right edge). Everything in between is untouched. So instead of recomputing the window's sum, count, or validity from nothing, you update a small piece of running state: undo the contribution of what left, add the contribution of what just entered. That update is O(1), and it's the entire reason sliding window beats brute force.

Sliding window is really just this: keep enough running state (a sum, a frequency map, a deque) that adding one element and removing one element is O(1) — and never re-touch the rest of the window at all.

02 · Two flavors

Fixed-size vs. variable-size windows

Every sliding window problem is one of two shapes, and telling them apart early saves a lot of confused debugging.

A quick tell: if the problem statement hands you an explicit window length, it's fixed-size. If it asks you to find the longest/shortest/best window such that some condition holds, it's variable-size.

a b c a b c b b r=2 left right window "abc" → len 3 a b c a b c b b r=3 left right a repeats → left jumps to 1 a b c a b c b b r=7 left · right window "b" → max stays 3

Three snapshots of the same window sliding through "abcabcbb": it grows on the right, then a repeated character forces left to jump forward, and the cycle continues to the end.

03 · Method

A repeatable framework

The same five decisions apply whether you're computing a sum, a count, or a maximum.

  1. 1 Decide fixed or variableDoes the problem give you a length (fixed), or ask you to find the best length (variable)?
  2. 2 Define "valid" preciselyWhat exact condition makes the current window acceptable — no duplicate characters, sum ≤ target, at most k distinct values?
  3. 3 Expand rightMove the right pointer forward, updating whatever running state you track — a count map, a running sum, a deque — as each new element enters.
  4. 4 Shrink left when invalidFor variable-size windows: only move left when the window becomes invalid, undoing that element's contribution to your running state as it leaves.
  5. 5 Update the answer at the right momentUsually right after confirming the window is valid — not on every single expansion, or you'll record windows that were never actually valid.

04 · Worked example

Longest Substring Without Repeating Characters, on "abcabcbb"

Variable-size window. State: a map of each character's most recent index, plus left, the start of the current window. Rule: whenever right lands on a character already present in the window, jump left to just past that character's previous occurrence — not one step, straight there. Track the longest valid window seen so far.

rightleftwindowmax len
0 → a0"a"1
1 → b0"ab"2
2 → c0"abc"3
3 → a1"bca"3
4 → b2"cab"3
5 → c3"abc"3
6 → b5"cb"3
7 → b7"b"3

The first three steps just grow the window — no repeats yet, so max len climbs to 3. At right=3 ('a'), the window already contains an 'a' at index 0, so left jumps to 1 (not 0+1 by coincidence — it's genuinely "one past the previous occurrence"). The same jump happens at right=6, where 'b''s previous occurrence was at index 4, so left jumps from 3 straight to 5, skipping over index 4 entirely rather than creeping forward one step at a time. From that point on every window is length ≤ 3, so the answer never improves again. Final answer: 3, the substring "abc".

Open the Longest Substring visualizer to watch this exact trace animate, character by character.

05 · Advanced technique

The monotonic deque trick — Sliding Window Maximum

"Maximum in every window of size k" looks like it needs O(n·k) — scan all k elements for every window position. A monotonic deque gets it down to O(n) total.

Keep a deque of indices (not values), maintained so the values they point to are always in decreasing order from front to back. When a new index arrives on the right:

Each index is pushed once and popped at most once, so the total work across the entire array is O(n), even though every individual window's maximum is available in O(1). This is the same monotonic-stack idea from the Stacks theory page, just applied at both ends of the structure instead of one.

Open the Sliding Window Maximum visualizer to watch the deque grow and shrink as the window moves.

06 · Complexity

How to reason about time & space

It looks like sliding window should be quadratic — there's a loop for right and, for variable windows, what reads like a nested loop for left. But left and right are each bounded by the array's length, and neither ever moves backward. Across the whole run, right advances at most n times and left advances at most n times — so the combined work is O(n) + O(n) = O(n), not O(n²), despite the nested-looking shape.

Space is whatever running state you need to check validity or track the max: O(k) for a fixed window of size k, O(alphabet size) for a character frequency map (bounded, so effectively constant for most string problems), or O(k) for a monotonic deque that never holds more than the current window's worth of indices.

07 · Before you start coding

Common mistakes

08 · Practice

Try it yourself

Both flavors covered above, ready to step through interactively.