Sliding Window
Grow the right edge, shrink the left, never restart.
- Brute force
- O(n²) — try every start, extend every end
- With the pattern
- O(n) — each index enters and leaves the window once
- Extra space
- O(k) — size of the alphabet / window state
In plain English
“Imagine reading a long necklace of colored beads through a cardboard tube you can stretch. You stretch the tube forward one bead at a time, and the moment you see a repeated color inside it, you pull the back end forward until the repeat is gone. The tube only ever moves forward, so you never re-read the necklace from scratch.”
Why it's fast
Brute force restarts at every left index and re-scans, re-counting the same characters over and over (O(n²) or worse). A window keeps a running summary (a set, a counter, a sum) and updates it incrementally: add one element on the right, remove one on the left. Because left and right only move forward, total work is O(n).
Spot it when the problem says…
- contiguous subarray / substring
- longest / shortest / maximum window such that…
- at most k distinct characters
- without repeating characters
- window of size k
- contains all characters of t (anagram / permutation)
Visualize
Longest substring without repeating characters
Given a string, find the length of the longest substring with all-unique characters.
seen (char → last index)
Window is empty. It will only ever grow on the right and shrink on the left.
1def longest_unique(s):2 seen = {} # char -> last index3 left = best = 04 for right, ch in enumerate(s):5 if ch in seen and seen[ch] >= left:6 left = seen[ch] + 1 # jump past the duplicate7 seen[ch] = right8 best = max(best, right - left + 1)9 return bestvariables
- left
- 0
- best
- 0
How to apply it
- 01Pick the state the window must track (set of chars,
Counter, running sum). - 02For each
right, adds[right]to the state. - 03While the window is invalid, remove
s[left]from the state andleft += 1. - 04Window
[left, right]is now valid — update the answer (right - left + 1). - 05For fixed-size windows, instead slide both ends together once the size reaches k.
Variations you'll meet
Variable window: longest valid
The visualizer's example — longest substring without repeats. Shrink while invalid, then record.
def length_of_longest_substring(s: str) -> int: seen = set() left = best = 0 for right, ch in enumerate(s): while ch in seen: # window invalid: shrink seen.remove(s[left]) left += 1 seen.add(ch) best = max(best, right - left + 1) return bestVariable window: shortest valid
Flip it: expand until valid, then shrink while still valid and record the minimum (Minimum Window Substring, Minimum Size Subarray Sum).
def min_subarray_len(target: int, nums: list[int]) -> int: left = total = 0 best = float("inf") for right, x in enumerate(nums): total += x while total >= target: # valid: try to shrink best = min(best, right - left + 1) total -= nums[left] left += 1 return 0 if best == float("inf") else bestFixed-size window
Add nums[i], subtract nums[i-k]. Great for averages, anagram checks with a 26-length count array.
Monotonic deque window
When you need the max/min inside each window, keep a deque of candidate indices (Sliding Window Maximum).
Common mistakes
- Off-by-one on window size: it's
right - left + 1, notright - left. - Using
ifinstead ofwhileto shrink, leaving the window still invalid. - Updating the answer before the window is valid again.
- Forgetting to delete a key from the
Counterwhen its count hits 0, solen(counter)is wrong for 'k distinct'. - Using sliding window on arrays with negative numbers for sum targets — shrinking no longer guarantees the sum drops (use prefix sums).
Practice ladder
Easy → hard. Tick them off as you go.
Think you've got it?
Let the AI interviewer throw a Sliding Window problem at you and grade how you explain it.