5. Вопрос 24. Два указателя и скользящее окно. Шаблон 2 — "НЕ МЕНЕЕ K раз", ищем МИНИМУМ


Шаблон 2 — "НЕ МЕНЕЕ K раз", ищем МИНИМУМ

Задача-пример

Найти минимальную подстроку, где буква X встречается не менее 2 раз.

Строка: A B X A X X A B

Принцип

1. Двигаем right вправо, пока условие не выполнено
2. Когда условие выполнено (X >= 2) — обновляем минимум и сужаем
3. Обновляем ответ внутри while, пока условие ещё выполняется

Пошаговый разбор
Строка: A B X A X X A B
        0 1 2 3 4 5 6 7

Начало: left=0, count_x=0, min_len=∞

Шаги 1-3: right=0,1,2

        A B X A X X A B
        ↑   ↑
        L   R
        
count_x = 1 (<2) — условие НЕ выполнено, просто идём дальше

Шаг 4: right=3, символ 'A'

        A B X A X X A B
        ↑     ↑
        L     R
        
count_x = 1 (<2) — условие НЕ выполнено

Шаг 5: right=4, символ 'X'

        A B X A X X A B
        ↑       ↑
        L       R
        
count_x = 2 (≥2 ) — условие ВЫПОЛНЕНО!

Входим в while, обновляем ВНУТРИ:
  min_len = min(∞, 4-0+1) = 5
  left=0: 'A' — сдвигаем, count_x=2
  
  min_len = min(5, 4-1+1) = 4
  left=1: 'B' — сдвигаем, count_x=2
  
  min_len = min(4, 4-2+1) = 3
  left=2: 'X' — сдвигаем, count_x=1 (<2) — выходим из while

        A B X A X X A B
              ↑   ↑
              L   R

Шаг 6: right=5, символ 'X'

        A B X A X X A B
              ↑     ↑
              L     R
        
count_x = 2 (≥2 ✓) — условие ВЫПОЛНЕНО!

Входим в while:
  min_len = min(3, 5-3+1) = 3
  left=3: 'A' — сдвигаем, count_x=2
  
  min_len = min(3, 5-4+1) = 2  ← НОВЫЙ МИНИМУМ!
  left=4: 'X' — сдвигаем, count_x=1 (<2) — выходим

        A B X A X X A B
                ↑   ↑
                L   R

Шаги 7-8: right=6,7

count_x остаётся 1 (<2) — условие не выполнено, while не срабатывает
Ответ: 2

Минимальная подстрока: X X (позиции 4-5)

Код

def min_at_least_k(s, k):
    left = 0
    count_x = 0
    min_len = float('inf')
    
    for right in range(len(s)):
        if s[right] == 'X':
            count_x += 1
        
        while count_x >= k:         # пока выполнено
            min_len = min(min_len, right - left + 1)  # ВНУТРИ while
            if s[left] == 'X':
                count_x -= 1
            left += 1
    
    return min_len

Ключевое правило Шаблона 2

┌─────────────────────────────────────────────┐
│  while count >= k   ← сужаем ПОКА выполнено │
│  обновляем ВНУТРИ while ← ловим минимум     │
└─────────────────────────────────────────────┘

time 1000 ms
memory 256 Mb

Комментарий учителя