Изучите технику скользящего окна в Python. Решайте задачи на подстроки и подмассивы за линейное время. Практические примеры и код.
Вы когда-нибудь застревали на задаче про самую длинную подстроку без повторяющихся символов? Первое, что приходит в голову — двойной цикл и множество. Но на длинной строке такой подход тормозит. Техника скользящего окна превращает квадратичное решение в линейное. Сегодня вы научитесь применять её на практике.
Скользящее окно — это способ поддерживать подмассив или подстроку, проходя по данным один раз. Вы двигаете два указателя (левый и правый) и обновляете состояние окна за O(1). Каждый элемент обрабатывается не более двух раз: когда входит в окно и когда выходит. Итоговая сложность — O(n).
У каждого окна есть инвариант — условие, которое должно выполняться. Например, для задачи «самая длинная подстрока без повторяющихся символов» инвариант: все символы в окне уникальны. Когда добавляете новый символ справа, проверяете инвариант. Если он нарушен — двигаете левый указатель, пока не восстановите инвариант.
Разберём классическую задачу LeetCode.
def length_of_longest_substring_bruteforce(s: str) -> int:
n = len(s)
best = 0
for i in range(n):
seen = set()
for j in range(i, n):
if s[j] in seen:
break
seen.add(s[j])
best = max(best, j - i + 1)
return bestДля строки длиной 10⁵ это будет работать вечность.
def length_of_longest_substring(s: str) -> int:
last_seen = {} # символ -> последний индекс
left = 0 # начало окна
best = 0
for right, ch in enumerate(s):
# если ch уже есть в окне, сдвигаем левую границу
if ch in last_seen and last_seen[ch] >= left:
left = last_seen[ch] + 1
last_seen[ch] = right
best = max(best, right - left + 1)
return bestЗдесь мы просто обновляем словарь и два указателя. Никаких вложенных циклов.
Дан массив положительных чисел и target. Найдите минимальную длину непрерывного подмассива, сумма которого не меньше target.
def min_subarray_len(target: int, nums: list[int]) -> int:
left = 0
current_sum = 0
best = float('inf')
for right, val in enumerate(nums):
current_sum += val # расширяем окно
while current_sum >= target:
best = min(best, right - left + 1)
current_sum -= nums[left]
left += 1
return 0 if best == float('inf') else bestКаждый элемент добавляется один раз и удаляется один раз — O(n) времени, O(1) памяти.
left = max(left, last_seen[ch] + 1) или while-цикл."", "aaaa" и строке из одного символа.Скользящее окно — мощный паттерн для задач на подстроки и подмассивы. Потренируйтесь прямо сейчас: возьмите задачу «максимальная сумма подмассива размера k» или «самая длинная подстрока с не более чем двумя различными символами». Напишите инвариант, нарисуйте указатели на бумаге и реализуйте решение. Когда почувствуете, как окно скользит, — вы готовы к собеседованию.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →