Courses › Coding Interviews › Patterns
Sliding Window
Fixed and variable windows for subarray and substring problems.
The sliding window pattern handles questions about contiguous subarrays or substrings. Instead of recomputing every window from scratch (O(n²) or worse), you maintain the window's state as it slides: add the element entering on the right, remove the one leaving on the left.
When to use it
- "Longest / shortest / count of subarrays or substrings such that…"
- The condition can be updated incrementally as elements enter and leave
- For variable windows, the condition is monotonic: if a window is valid, shrinking it keeps it valid (or expanding keeps it invalid)
[!WARNING] Negative numbers break it "Subarray with sum k" with negative numbers isn't monotonic — growing the window can decrease the sum. Use prefix sums + a hash map instead (see Hash Maps & Sets).
Fixed-size window
def max_window_sum(nums, k):
window = sum(nums[:k])
best = window
for i in range(k, len(nums)):
window += nums[i] - nums[i - k]
best = max(best, window)
return bestVariable-size window: the template
def variable_window(s):
left = 0
state = {} # whatever describes the current window
best = 0
for right, ch in enumerate(s):
# 1. add s[right] to the state
# 2. while the window is invalid, remove s[left] and advance left
# 3. the window [left, right] is valid: update the answer
...
return bestLongest substring without repeating characters
def length_of_longest_substring(s):
last_seen = {}
left = best = 0
for right, ch in enumerate(s):
if last_seen.get(ch, -1) >= left:
left = last_seen[ch] + 1 # jump past the previous occurrence
last_seen[ch] = right
best = max(best, right - left + 1)
return bestMinimum window containing all target characters
For "shortest" problems, flip the loop: expand until valid, then shrink while still valid, recording the answer during the shrink.
from collections import Counter
def min_window(s, t):
need = Counter(t)
missing = len(t)
left = 0
best = (float("inf"), 0, 0)
for right, ch in enumerate(s):
if need[ch] > 0:
missing -= 1
need[ch] -= 1
while missing == 0:
if right - left + 1 < best[0]:
best = (right - left + 1, left, right + 1)
need[s[left]] += 1
if need[s[left]] > 0:
missing += 1
left += 1
return s[best[1]:best[2]] if best[0] != float("inf") else ""Complexity
Each element enters and leaves the window at most once: O(n) time, with O(k) or O(alphabet) space for the window state.
[!TIP] Practice Longest Substring Without Repeating Characters · Minimum Window Substring