🪟 Sliding Window Technique
Maintains a “window” (a contiguous subarray/substring) that expands and shrinks as it slides across the data, avoiding recomputation from scratch at every position. Turns many O(n²) or O(n³) brute-force problems into O(n).
Pattern 1: Fixed-Size Window
def max_sum_subarray(arr, k):
window_sum = sum(arr[:k]) # compute the FIRST window directly
max_sum = window_sum
for i in range(k, len(arr)):
window_sum += arr[i] - arr[i - k] # slide: add new element, remove the one that fell out
max_sum = max(max_sum, window_sum)
return max_sum
max_sum_subarray([2, 1, 5, 1, 3, 2], 3) # 9, from [5, 1, 3]The core trick: incremental updates instead of recomputation
Recomputing
sum(arr[i:i+k])fresh at every position is O(n*k) overall. Sliding the window by subtracting the outgoing element and adding the incoming one keeps each step O(1), for O(n) total.
Pattern 2: Variable-Size Window (Expand and Shrink)
Used when the window size isn’t fixed, it grows while a condition holds and shrinks when it’s violated.
def smallest_subarray_with_sum(arr, target):
left = 0
current_sum = 0
min_length = float("inf")
for right in range(len(arr)):
current_sum += arr[right] # expand the window
while current_sum >= target:
min_length = min(min_length, right - left + 1)
current_sum -= arr[left] # shrink from the left
left += 1
return min_length if min_length != float("inf") else 0
smallest_subarray_with_sum([2, 1, 5, 2, 3, 2], 7) # 2, from [5, 2]Longest Substring Without Repeating Characters
def longest_unique_substring(s):
seen = {}
left = 0
max_length = 0
for right, char in enumerate(s):
if char in seen and seen[char] >= left:
left = seen[char] + 1 # jump the window start PAST the duplicate
seen[char] = right
max_length = max(max_length, right - left + 1)
return max_length
longest_unique_substring("abcabcbb") # 3, "abc"Covered in more depth in String Algorithms, included here since it’s the canonical variable-window example.
Minimum Window Substring (Harder Variant)
from collections import Counter
def min_window(s, t):
if not t or not s:
return ""
need = Counter(t)
missing = len(t) # total characters still needed
left = 0
best_left, best_right = 0, float("inf")
for right, char in enumerate(s, 1):
if need[char] > 0:
missing -= 1
need[char] -= 1
while missing == 0: # window contains everything needed, try to shrink it
if right - left < best_right - best_left:
best_left, best_right = left, right
need[s[left]] += 1
if need[s[left]] > 0:
missing += 1
left += 1
return s[best_left:best_right] if best_right != float("inf") else ""
min_window("ADOBECODEBANC", "ABC") # 'BANC'Maximum Sliding Window (Using a Deque)
Already covered in depth in Queues and Deques, included here as a cross-reference since it’s fundamentally a sliding window problem paired with a monotonic deque for O(1) max retrieval per step.
Sliding Window vs Two Pointers
They're closely related, not identical
Sliding window specifically deals with CONTIGUOUS subarrays/substrings, tracking a running aggregate (sum, count, frequency map) as the window moves. Two pointers (Two Pointers Technique) is the more general pattern, pointers don’t have to define a contiguous window and don’t always move in the same direction. Many sliding window problems ARE a form of two pointers, but not all two-pointer problems involve a window.
Recognizing Sliding Window Problems
Signals to watch for
- The problem involves a CONTIGUOUS subarray or substring.
- Keywords: “longest”, “shortest”, “maximum sum of size k”, “smallest window containing”.
- A brute force would check every possible contiguous range, an obvious O(n²) or worse starting point that a window can usually collapse to O(n).