name: Sliding Window slug: sliding-window difficulty_level: 2 description: > Maintain a window of elements that slides through the data, tracking a constraint or computing aggregates. This transforms O(n*k) brute force into O(n) by incrementally updating the window instead of recalculating from scratch. when_to_use: | - Finding subarrays/substrings with specific properties - Maximum/minimum sum of fixed-size windows - Longest substring with at most K distinct characters - Problems mentioning "contiguous" elements metaphor: | Imagine looking at a landscape through a train window. As the train moves forward, the scenery at the back of your view disappears while new scenery appears at the front. You don't need to memorize the entire journey—just keep track of what's currently visible through your window. Another analogy: a cashier's sliding tray at a bank. As new items are added to one end, old items fall off the other. You only count what's on the tray at any moment. core_concept: | The **sliding window** technique avoids redundant computation by maintaining state as the window moves. Instead of recalculating the entire window each time, you *add* what enters and *remove* what leaves. There are two main types: 1. **Fixed-size window**: Window size is constant (e.g., "find max sum of k elements") 2. **Variable-size window**: Window expands and contracts based on constraints (e.g., "longest substring with at most 2 distinct characters") The key insight is that consecutive windows share most of their elements. Only the edges change, so only update those. visualization: | **Example: Maximum sum of 3 consecutive elements** ``` Array: [2, 1, 5, 1, 3, 2] Window size: 3 Window 1: [2, 1, 5] = 8 (calculate full sum) └─────┘ Window 2: [1, 5, 1] = 8-2+1 = 7 (remove 2, add 1) └─────┘ Window 3: [5, 1, 3] = 7-1+3 = 9 (remove 1, add 3) ← Maximum! └─────┘ Window 4: [1, 3, 2] = 9-5+2 = 6 (remove 5, add 2) └─────┘ ``` **Variable window: Longest substring with at most 2 distinct chars** ``` String: "eceba" "e" → 1 distinct, expand → length 1 "ec" → 2 distinct, expand → length 2 "ece" → 2 distinct, expand → length 3 ← Answer! "eceb" → 3 distinct, shrink from left "ceb" → 3 distinct, shrink from left "eb" → 2 distinct, expand → length 2 "eba" → 3 distinct, shrink... ``` code_template: | def fixed_window(arr: list, k: int) -> int: """Fixed-size sliding window.""" n = len(arr) if n < k: return 0 # Calculate initial window window_sum = sum(arr[:k]) max_sum = window_sum # Slide the window for i in range(k, n): window_sum += arr[i] - arr[i - k] # Add new, remove old max_sum = max(max_sum, window_sum) return max_sum def variable_window(s: str, k: int) -> int: """Variable-size sliding window.""" char_count = {} left = 0 max_length = 0 for right in range(len(s)): # Expand: add character at right char_count[s[right]] = char_count.get(s[right], 0) + 1 # Contract: shrink from left if constraint violated while len(char_count) > k: char_count[s[left]] -= 1 if char_count[s[left]] == 0: del char_count[s[left]] left += 1 # Update answer max_length = max(max_length, right - left + 1) return max_length recognition_signals: - "contiguous subarray" - "substring" - "maximum sum of k elements" - "window" - "consecutive" - "at most k distinct" - "minimum window" - "longest substring" - "sliding" common_mistakes: - title: Forgetting to handle window smaller than required description: | When array length is less than window size k, trying to create a window causes index errors or incorrect results. fix: | Add an early check: ```python if len(arr) < k: return 0 # or appropriate default ``` - title: Off-by-one in variable window description: | When calculating window length, using `right - left` instead of `right - left + 1` gives length off by one. fix: | Window length is always `right - left + 1` (inclusive on both ends). - title: Not cleaning up empty entries in hash map description: | When shrinking a variable window, decrementing a counter to 0 but not removing the key causes the distinct count to be wrong. fix: | Always delete keys when count reaches 0: ```python if char_count[s[left]] == 0: del char_count[s[left]] ``` - title: Updating answer at wrong time description: | For "minimum" problems, updating the answer inside the while loop captures invalid states. For "maximum" problems, updating only inside the while loop misses valid states. fix: | For maximum problems, update after expanding. For minimum problems, update when the constraint is first satisfied (inside the while loop). variations: - name: Fixed-size window description: | Window size stays constant throughout. Simple slide operation: add one element, remove one element. example: "Maximum Sum Subarray of Size K, Find All Anagrams" - name: Variable-size (shrinkable) description: | Window expands freely but contracts when constraints are violated. Uses a while loop to shrink until valid. example: "Longest Substring Without Repeating, Minimum Window Substring" - name: Two-pointer variant description: | Some problems use two pointers that feel like sliding window but track different metrics. The mechanics are similar. example: "Container With Most Water, Trapping Rain Water" - name: Caterpillar method description: | Another name for the variable sliding window, emphasizing how the window stretches and contracts like a caterpillar moving. example: "Common in competitive programming contexts" related_patterns: - two-pointers - prefix-sum prerequisite_patterns: - two-pointers