Sliding Window
โฑ๏ธ ~2-minute bite ยท solve the sandbox to master
5-Year-Old Metaphor
โ The physical, real-world picture. No jargon.๐ A magnifying glass gliding over a film strip โ never re-reading a frame it already passed.
The naive approach (what most people write first)
You have a strip of 8 film frames: [2, 1, 5, 1, 3, 2, 4, 1]. Find the 3 brightest consecutive frames.
The brute force approach: place the glass at frame 0, sum frames 0+1+2. Move it to frame 1, sum frames 1+2+3 from scratch. Move it to frame 2, sum frames 2+3+4 from scratch. You re-read frames 1 and 2 on the second pass. You re-read frames 2 and 3 on the third. Every frame gets touched roughly k times. For 10,000 frames and k=100 that's 1,000,000 operations.
The sliding trick (the aha moment)
When you slide the glass one frame to the right, only two things change:
- One new frame enters from the right โ add it
- One old frame falls off the left โ subtract it
- Everything in the middle is the same sum as before
That's one addition + one subtraction per slide. For the same 10,000 frames and k=100 that's 10,000 operations โ 100ร faster.
Visualised step-by-step
When to reach for this pattern
- Problem mentions "contiguous subarray" or "substring"
- There's a fixed size k or a constraint like "sum โค target"
- You need to find max/min/count over a range that moves through the array
- The array doesn't need to be sorted
โ ๏ธ Pitfall: variable window with negatives + "sum โค target" โ shrinking the window doesn't reliably decrease the sum. Use prefix sums + hashmap instead.
Interactive Sandbox
โ Move something, see it react instantly.k=3 means you look at 3 consecutive elements at a time.
2
window sum
2
best sum โ
1 / 8
step
Challenge
Set the window size so the best window sum is maximized, then play to the end. (Hint: optimal k = 8.)
Why Should I Care?
โ The exact interview question + the bug it kills.Exact interview question (fixed window)
"Given an integer array and integer k, return the maximum sum of any contiguous subarray of size k."
| 1 | function maxSum(arr: number[], k: number): number { |
| 2 | let sum = 0, best = -Infinity; |
| 3 | for (let r = 0; r < arr.length; r++) { |
| 4 | sum += arr[r]; // add entering element |
| 5 | if (r >= k - 1) { |
| 6 | best = Math.max(best, sum); |
| 7 | sum -= arr[r - k + 1]; // drop leaving element |
| 8 | } |
| 9 | } |
| 10 | return best; |
| 11 | } |
| 12 | // Time: O(n) ยท Space: O(1) |
Harder variant (variable window) โ very common at FAANG
"Find the length of the longest substring without repeating characters."
| 1 | function lengthOfLongestSubstring(s: string): number { |
| 2 | const seen = new Map<string, number>(); // char โ last index |
| 3 | let left = 0, best = 0; |
| 4 | for (let right = 0; right < s.length; right++) { |
| 5 | const c = s[right]; |
| 6 | if (seen.has(c) && seen.get(c)! >= left) { |
| 7 | left = seen.get(c)! + 1; // shrink: jump past duplicate |
| 8 | } |
| 9 | seen.set(c, right); |
| 10 | best = Math.max(best, right - left + 1); |
| 11 | } |
| 12 | return best; |
| 13 | } |
| 14 | // Time: O(n) ยท Space: O(min(n, alphabet)) |
Complexity comparison
| Approach | Time | Space |
|---|---|---|
| Brute force (nested loops) | O(nยทk) | O(1) |
| Sliding window | O(n) | O(1) fixed / O(k) variable |
Production bugs this pattern prevents
- Rate limiter "requests in the last 60s" โ naive implementation scans the full timestamp array on every request. With sliding window + circular buffer, each check is O(1). At 50k RPS, the difference is thread-blocking vs invisible.
- Moving average chart โ a dashboard that recomputes average over the last N data points from scratch on every new point melts the main thread when N is large. Sliding window makes each tick O(1): add new value, subtract oldest.
- Streaming percentiles โ approximating p99 latency over a sliding time window. Same pattern: add incoming, evict expired.
The Deep Dive
โ Spec refs, engine internals, the minutiae.Two flavors โ know which the question wants
Fixed window
- Width k is given upfront
- Both pointers move in lockstep (right = left + k)
- O(n) time, O(1) space
- Works with negatives
- Examples: max sum of size k, product of k consecutive
Variable window
- Constraint drives the size (sum โค target, k distinct chars)
- Expand right freely, shrink left when constraint breaks
- O(n) amortized, O(k) space for a hashset/map
- Breaks with negatives + "sum โค target"
- Examples: longest substring, minimum window substring
The amortisation argument (what interviewers probe)
Variable window looks O(nยฒ) because there's a while (shrink) inside a for (expand). The interviewer will ask: "wait, isn't this nested?"
The correct answer: each element is visited at most twice โ once when right passes it (it enters the window), once when left passes it (it leaves). Since left only ever moves forward and can advance at most n times total across the entire outer loop, the sum of all inner iterations โค n. Total work = O(2n) = O(n).
This is the same argument as the two-pointer amortization. If you can articulate it clearly in an interview, it signals a strong algorithmic foundation.
When sliding window breaks down
- Negatives + variable window + "sum โค target" โ shrinking the window might not decrease the sum if negative elements are inside. The monotonicity assumption breaks. Switch to prefix sums + sorted structure or prefix sums + hashmap.
- Non-contiguous constraints โ if elements can be skipped (pick any k elements), window doesn't apply; use sorting + greedy or DP.
- 2D arrays โ for "max sum rectangle", you can collapse rows using prefix sums to reduce to a 1D sliding window problem. O(nยฒยทm) โ O(nยฒยทm) but with a manageable constant.
Common implementation bugs
- Off-by-one on window open: the window is "full" at index
k-1, notk. Check withif (r >= k - 1)before recording best. - Not initialising best to
-Infinity: initialising to 0 breaks for all-negative arrays (the correct answer may be a negative number). - Hashmap not evicting stale entries: in the "no-repeat characters" pattern, you must check
seen.get(c) >= leftbefore jumping โ the map may contain a prior occurrence that's already outside the window.
Related patterns to know next
- Two Pointers โ sibling pattern; same left/right idea but for sorted arrays (no hashmap needed)
- Prefix Sums โ when range queries aren't contiguous or you need O(1) range sums after O(n) pre-processing
- Monotonic Deque โ sliding window maximum (not sum) in O(n) using a deque that maintains a descending max
- Kadane's Algorithm โ maximum subarray sum with no fixed size constraint (dynamic programming, not sliding window)
Interview Questions
โ Real questions from real interviews โ with answers.Use sliding window when the problem involves a contiguous subarray/substring and a constraint you can maintain incrementally.
Fixed window slides one step at a time; variable window shrinks the left pointer until the constraint is satisfied.
Check that the stored index is still inside the current window before jumping left.
O(n + m) โ each character is visited at most twice (once by right, once by left).
A monotonic deque of timestamps โ evict entries older than the window, count the rest.
Memory Game
โ Quick quiz โ lock the concept in long-term memory.When sliding a variable window, in what order should the right and left pointers move?