Lesson 3 of 8 · 48 min
Sliding window
Fixed and variable sliding windows, the at-most-K template, minimum window covering, amortized O(n) reasoning, and production metaphors for rolling metrics.
Contiguous + constraint = window, not DP first
Key idea
Fixed window: max sum of size K
1FIXED WINDOW — max sum of size k23def max_sum_k(a: list[int], k: int) -> int:4 if k <= 0 or k > len(a):5 raise ValueError("bad k")6 s = sum(a[:k])7 best = s8 for i in range(k, len(a)):9 s += a[i] - a[i - k]10 best = max(best, s)11 return best1213# O(n) time, O(1) space. Narrate edges: k==n → whole array once.Variable window: longest substring without repeating chars
1VARIABLE WINDOW — longest substring without repeating characters23def length_of_longest_substring(s: str) -> int:4 last: dict[str, int] = {}5 l = 06 best = 07 for r, ch in enumerate(s):8 if ch in last and last[ch] >= l:9 l = last[ch] + 1 # shrink past previous ch10 last[ch] = r11 best = max(best, r - l + 1)12 return best1314# Dry-run "abba": r=0 a; r=1 b; r=2 b -> l=2; r=3 a -> l=1? last[a]=0 < l=2 so l stays 2;15# actually last[a] updated careful: at r=3, last[a]=0 < l=2, best max with len 1…16# Trace fully in interview — off-by-one here is common.The “at most K” template
1AT MOST K DISTINCT — count subarrays (template gold)23from collections import defaultdict45def at_most_k_distinct(a: list[int], k: int) -> int:6 if k < 0:7 return 08 freq: dict[int, int] = defaultdict(int)9 l = 010 distinct = 011 ans = 012 for r, x in enumerate(a):13 if freq[x] == 0:14 distinct += 115 freq[x] += 116 while distinct > k:17 freq[a[l]] -= 118 if freq[a[l]] == 0:19 distinct -= 120 l += 121 ans += r - l + 1 # all subarrays ending at r22 return ans2324def exactly_k_distinct(a, k):25 return at_most_k_distinct(a, k) - at_most_k_distinct(a, k - 1)Key idea
Minimum window substring (harder variable window)
Common mistake
“Sliding window always uses two pointers on an array; strings are different.”
Common mistake
“If I need exactly K, I should maintain exactly K in the window with complex updates.”
When the left pointer moves — force the sentence
1MIN WINDOW COVERING t — formed/need counters (skeleton)23from collections import Counter45def min_window(s: str, t: str) -> str:6 need = Counter(t)7 missing = len(t)8 best = (0, float("inf")) # start, end exclusive9 l = 010 for r, ch in enumerate(s):11 if need[ch] > 0:12 missing -= 113 need[ch] -= 114 while missing == 0:15 if r + 1 - l < best[1] - best[0]:16 best = (l, r + 1)17 need[s[l]] += 118 if need[s[l]] > 0:19 missing += 120 l += 121 return "" if best[1] == float("inf") else s[best[0]:best[1]]2223# O(|s|+|t|). Dry-run s="ADOBECODEBANC", t="ABC" in the interview.Key idea
Sliding Window Maximum / window technique family — NeetCode style explainersNeetCodeInterview prep
- 01“How do you recognize sliding window?” → contiguous subarray/substring + monotonic constraint on the segment.
- 02“When does L move?” → while window invalid (or while you can shrink and stay optimal for min-window).
- 03“Exactly K distinct?” → atMost(K) − atMost(K−1); explain why each ending index contributes r−l+1.
- 04“Fixed vs variable?” → fixed size K vs grow/shrink on predicate.
- 05“Min window covering t?” → expand until cover, shrink while cover, track best bounds.
- 06“Complexity?” → O(n) amortized if L,R each move ≤n and updates O(1)/O(σ).
- 07“Production story?” → rolling latency, session length with ≤K error types, rate windows.
- 08“Common bug?” → forgetting to update freq when jumping L; off-by-one on best length.
- 09"Min window state?" -> need map + missing count; expand; shrink while valid; track best.
- 10"Why deque for window max?" -> expire front; pop back; O(1) max; heap lacks O(1) delete.
- 11"Exactly K?" -> atMost(K) - atMost(K-1).
- 12"Rate limit window?" -> timestamp queue; pop expired; reject if len >= limit.
articleSliding Window pattern overviewAlgoMasterdocsNeetCode — Longest Substring Without Repeating CharactersNeetCodearticleLeetCode Discuss — Sliding Window templatesLeetCode DiscussarticleTech Interview Handbook study planTech Interview HandbookName the validity predicate in one sentence before you touch L and R. If the predicate is not monotonic, stop and reconsider the pattern.
Hard templates: min window + sliding max
1MINIMUM WINDOW SUBSTRING — need/have (LC 76)23from collections import Counter45def min_window(s: str, t: str) -> str:6 if not t or not s:7 return ""8 need = Counter(t)9 missing = len(t)10 best_l, best_len = 0, float("inf")11 l = 012 for r, ch in enumerate(s):13 if need[ch] > 0:14 missing -= 115 need[ch] -= 116 while missing == 0:17 if r - l + 1 < best_len:18 best_l, best_len = l, r - l + 119 need[s[l]] += 120 if need[s[l]] > 0:21 missing += 122 l += 123 return "" if best_len == float("inf") else s[best_l:best_l + best_len]2425# Dry-run ADOBECODEBANC / ABC -> BANC. O(|s|+|t|).1SLIDING WINDOW MAXIMUM — monotonic deque23from collections import deque45def max_sliding_window(nums: list[int], k: int) -> list[int]:6 dq: deque[int] = deque() # indices, nums decreasing7 out: list[int] = []8 for i, x in enumerate(nums):9 while dq and dq[0] <= i - k:10 dq.popleft()11 while dq and nums[dq[-1]] <= x:12 dq.pop()13 dq.append(i)14 if i >= k - 1:15 out.append(nums[dq[0]])16 return out # O(n) amortized; each index enter/leave onceCommon mistake
"Exactly K distinct is a single pass with == K checks."
Common mistake
"Recompute max(freq.values()) every step in character replacement."
Key idea
Longest Substring Without Repeating — NeetCodeNeetCode
Sliding Window Technique — takeUforwardtakeUforwardarticleSliding Window cheatsheet — TIHTech Interview HandbookCheckpoint
“Longest subarray with at most K distinct integers.” You start writing a DP table dp[i][k]. Better first move?
Checkpoint
In the count-subarrays at-most-K template, why add (r − l + 1) for each r?
Checkpoint
Minimum window substring: window is valid covering t. Next operation for global minimum?
Checkpoint
Production prompt: longest contiguous session of events with ≤3 error codes. Which map?
Checkpoint
You need number of subarrays with exactly 2 distinct integers. Cleanest approach?
Can you derive the at-most-K template from scratch and dry-run L moves on a 6-element example?
Takeaways
- Contiguous + monotonic constraint → sliding window before DP.
- Fixed K vs variable L/R; validity predicate is the design center.
- atMost(K) − atMost(K−1) for exactly K; add (r−l+1) when counting.
- Min window: expand to valid, shrink while valid, track best.
- Production: rolling latency, rate windows, session segments.
Next: hashmaps, prefix sums, and subarray sum K — frequency maps that turn O(n²) into O(n).
Sources
Free to read · better with Enzo
Learn it with Enzo
Save your progress, answer the checkpoints, and let Enzo quiz you on what you just read.