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
