Модуль 9 · Скользящее окно · ОП.04

Алгоритмы на массивах · модуль 9 · скользящее окно

Глава 9.1

9.1

Скользящее окно
на собеседованиях и в работе

В этой главе разобрано, откуда известно, что техника скользящего окна нужна. Сначала — какие задачи на подотрезки дают на алгоритмической секции и в каких программах подготовки окно выделено отдельной темой. Затем — где тот же приём работает в обычных программах. В конце — определение окна, его связь с двумя указателями из модуля 8, две формы окна и карта модуля.

Категория
Обзор темы
Уровень
Начальный
Опирается на
Модуль 8: указатели в одну сторону; занятие 7: срезы и полуинтервалы
Зачем это знать
Понимать, какие задачи модуля встретятся на интервью

§1Задачи на подотрезок на секции

Подотрезок массива — несколько элементов, которые стоят подряд: a[2], a[3], a[4]. В Python это срез a[2:5] из занятия 7. Задачи на подотрезки встречаются на алгоритмической секции с первого этапа. В журнале Яндекс Образования, в статье об алгоритмических собеседованиях, обе типичные задачи секции — про подотрезки.

«Типичный пример первой задачи: в массиве из чисел нужно найти наибольший неубывающий подотрезок, то есть такой подотрезок из чисел, где каждое следующее число больше или равно предыдущему».

«Типичный пример второй задачи: дан массив чисел, требуется найти число подмассивов, в которых значения всех чисел различны».

Там же

У массива из n элементов около n²/2 подотрезков, поэтому перебрать их все и для каждого посчитать ответ заново — это O(n²) или дольше. Скользящее окно проходит подотрезки по порядку и пересчитывает ответ по изменению: что вошло в подотрезок и что из него вышло. Первую задачу из цитаты решают одним проходом с текущей длиной подотрезка. Вторую — окном переменной длины со словарём, это тема занятия 10. Окно фиксированной длины, тема этого модуля, — самая простая форма приёма: длина подотрезка задана, и при каждом сдвиге в окно входит ровно один элемент и ровно один выходит.

Что требуется на секцииГде это в модуле
Решение одним проходом вместо перебора всех подотрезковГлавы 9.3, 9.4: пересчёт окна за O(1) и лучший отрезок длины k
Учёт крайних случаевГлава 9.6: k = 0, k = 1, k = n, k больше n
Обоснование сложностиГлава 9.7: замер пересчёта окна против суммы каждого среза
Вопросы до кодаГлава 9.2: формулировки задач и уточнения

§2Где окно стоит отдельной темой

В программах подготовки к собеседованиям на LeetCode скользящее окно выделено отдельным разделом. Состав разделов проверен по данным сайта.

ПрограммаРаздел Sliding WindowКакая форма окна
LeetCode 75643, 1456, 1004, 1493Первые две задачи — окно фиксированной длины, две следующие — переменной
LeetCode · Top Interview 150209, 3, 30, 76Все четыре — окно переменной длины, занятие 10

Раздел LeetCode 75 начинается с окна фиксированной длины: на нём проще всего увидеть, как сумма окна пересчитывается при сдвиге. Задачи на окно переменной длины используют тот же сдвиг, но длина окна в них меняется по условию.

§3Задачи с собеседований

У всех задач ниже на LeetCode стоит метка Sliding Window, это проверено по данным сайта. Первые шесть — окно фиксированной длины, остальные используют окно вместе с техниками из следующих занятий.

Номер и названиеСложностьЧто нужно сделатьГде в курсе
643 · Maximum Average Subarray IEasyНайти отрезок длины k с наибольшим среднимМодуль 9, лучший отрезок длины k
1456 · Maximum Number of Vowels in a Substring of Given LengthMediumНайти подстроку длины k, в которой больше всего гласныхМодуль 9, счётчик в окне
1343 · Number of Sub-arrays of Size K and Average Greater than or Equal to ThresholdMediumПосчитать отрезки длины k со средним не меньше порогаМодуль 9
2379 · Minimum Recolors to Get K Consecutive Black BlocksEasyНайти отрезок длины k, где меньше всего белых клетокМодуль 9
1052 · Grumpy Bookstore OwnerMediumВыбрать отрезок из k минут, который даёт больше всего довольных покупателейМодуль 9
2090 · K Radius Subarray AveragesMediumДля каждого элемента найти среднее окна радиуса k вокруг негоМодуль 9
219 · Contains Duplicate IIEasyПроверить, есть ли два равных элемента на расстоянии не больше kОкно и множество, занятие 19
438 · Find All Anagrams in a StringMediumНайти все подстроки, которые являются перестановкой образцаОкно и частотный словарь, занятие 18
239 · Sliding Window MaximumHardДля каждого окна длины k найти максимумОкно и дек, занятие 25
209 · Minimum Size Subarray SumMediumНайти самый короткий отрезок с суммой не меньше SОкно переменной длины, занятие 10
3 · Longest Substring Without Repeating CharactersMediumНайти самую длинную подстроку без повторовОкно переменной длины, занятие 10

Задачи 209 и 3 — практика занятия 10, в КТП она записана так: «Решить задачи на минимальный отрезок с суммой не меньше S и подстроку без повторов». Для занятия 9 КТП ставит другие две задачи: «Найти лучший отрезок длины k и максимальное число событий в фиксированном временном окне».

§4Где приём работает в программах

Окно фиксированной длины встречается везде, где по ряду значений считают показатель за последние k значений или за последние N секунд.

Где встречается
  • Скользящее среднее. В аналитике и на графиках курсов валют сглаживают ряд: каждую точку заменяют средним последних k значений. В библиотеке pandas для этого есть метод rolling(k), пример ниже.
  • Последние k событий. В стандартной библиотеке Python очередь collections.deque(maxlen=k) хранит не больше k элементов: при добавлении нового самый старый удаляется. Так хранят, например, последние строки журнала.
  • Счётчики за последние N секунд. «Сколько запросов пришло за последнюю минуту», «сколько ошибок за последние пять минут» — в мониторинге и при ограничении частоты запросов. С каждым новым моментом времени в окно входят новые события и из него выходят устаревшие. Это задача о событиях во временном окне, глава 9.5.

Число посетителей сайта по часам, сумма за каждые три часа подряд. Первые два значения — nan: для них трёх значений ещё нет.

Терминалpandas 3.0.6 · Python 3.12
>>> import pandas as pd
>>> visits = pd.Series([12, 15, 9, 20, 18, 7, 25])
>>> visits.rolling(3).sum().tolist()
[nan, nan, 36.0, 44.0, 47.0, 45.0, 50.0]
Терминалpython -i · Python 3.12
>>> from collections import deque
>>> last = deque(maxlen=3)
>>> for x in [5, 1, 4, 2, 8]:
...     last.append(x)
...     print(list(last))
...
[5]
[5, 1]
[5, 1, 4]
[1, 4, 2]
[4, 2, 8]

В обоих примерах окно длины 3 сдвигается на одну позицию: справа добавляется новое значение, слева уходит самое старое. В модуле этот сдвиг пишется вручную на обычном списке, без библиотек: так видно, сколько работы стоит каждый сдвиг.

§5Окно и его сдвиг

Перед определениями — пример из жизни, на котором видно, как работает сдвиг окна.

Для наглядности
Окно вагона

Поезд едет вдоль ряда столбов, в окне вагона всегда видно три столба. Когда поезд проезжает на один столб вперёд, справа в окне появляется новый столб, а слева один исчезает. Два столба посередине остаются, их не нужно разглядывать заново.

Что это в коде

Ряд столбов — список, окно — три соседних элемента a[l:l + 3]. Сдвиг окна — l += 1. Чтобы узнать сумму в новом окне, достаточно вычесть ушедший элемент и прибавить пришедший.

Где сравнение неточноПоезд едет непрерывно, а окно в алгоритме сдвигается ровно на один элемент за шаг. И окно не останавливается раньше времени: алгоритм проходит все окна от первого до последнего.

Теперь то же самое точными словами.

Окноwindow · полуинтервал [l, r)

Подотрезок списка, который задаётся двумя индексами: l — первый элемент окна, r — первый элемент за окном. В окно входят a[l], a[l + 1], …, a[r − 1], это срез a[l:r]. Длина окна — r − l: при записи полуинтервалом, как в занятии 7, длина считается без + 1.

Скользящее окно фиксированного размераfixed-size sliding window

Техника прохода, в которой окно длины k стоит сначала на a[0:k], а затем сдвигается на одну позицию вправо, пока не дойдёт до конца списка. Всего окон n − k + 1. При каждом сдвиге в окно входит один элемент справа и один выходит слева.

Ответ для окна — сумма, число гласных, количество событий — хранится в переменной, её называют состоянием окна. При сдвиге состояние не считают заново, а исправляют по двум элементам, которые изменились. Поэтому сдвиг стоит O(1), а весь проход — O(n).

Блок ниже показывает окно над списком посещений из §4. Кнопка «сдвинуть окно» делает один сдвиг и показывает, как пересчитывается сумма. Длину окна можно менять. Под лентой два счётчика обращений к элементам списка: сколько их было бы, если считать сумму каждого окна заново, и сколько нужно при сдвиге.

На семи значениях с k = 3 разница небольшая: 15 обращений против 11. Она растёт с длиной окна. Пересчёт с нуля читает k элементов для каждого из n − k + 1 окон, сдвиг — k элементов для первого окна и по два для каждого следующего.

nkПересчёт с нуля: (n − k + 1)·kСдвиг окна: k + 2·(n − k)
731511
100 0001009 990 100199 900
1 000 0001 000999 001 0001 999 000

Пересчёт с нуля стоит O(n·k): при k, сравнимом с n, это O(n²). Сдвиг окна стоит O(n) при любом k. Подробно оба способа и замер разобраны в главах 9.3 и 9.7.

§6Окно и два указателя

Границы окна l и r — это два указателя из модуля 8. Оба идут слева направо и назад не возвращаются, как указатели чтения и записи. Отличие в том, что расстояние между ними постоянно: r − l = k на каждом шаге. Поэтому оба указателя сдвигаются вместе, и в коде часто хранят только один из них.

Указатели в одну сторону, модуль 8Окно фиксированной длины, модуль 9
Указателиr читает, w пишетl — начало окна, r = l + k — конец
Расстояние между нимиМеняется: w отстаёт от r на число пропущенных элементовВсегда k
Что меняется на шагеСписок: запись в позицию wСостояние окна: сумма, счётчик
МонотонностьОба только вправо, отсюда O(n)Оба только вправо, отсюда O(n)

§7Две формы окна

Задачи на окно делятся на две формы по тому, как задаётся длина окна. Форму узнают по условию задачи.

Фиксированной длиныПеременной длины
Как задана длинаЧислом k в условии: «отрезок длины k», «за любые 3 часа подряд»Условием: «сумма не меньше S», «без повторов»
Как двигаются границыВместе, на одну позицию за шагПравая расширяет окно, левая сжимает, когда условие нарушено
Сколько оконРовно n − k + 1Зависит от данных
ПримерLeetCode 643, 1456LeetCode 209, 3
Где в курсеЗанятие 9, этот модульЗанятие 10

§8Карта модуля

Модуль построен так же, как модуль 8: от того, как задачу формулируют и уточняют, к решению, крайним случаям и замеру. Главы 9.1 и 9.2 — про условие, 9.3–9.5 — про сами алгоритмы, 9.6 и 9.7 — про проверку. Глава 9.8 проводит новую задачу через все этапы собеседования, 9.9 собирает ошибки модуля и объяснение решения, 9.10 — практика и домашнее задание, 9.11 — тренажёр в формате собеседования.

  1. 9.2 Формулировки и вопросы до решения. Как звучат задачи на окно фиксированной длины и что уточнить до кода.
  2. 9.3 Окно и пересчёт за O(1). Сумма каждого среза против сдвига окна, состояние окна, пошаговый прогон.
  3. 9.4 Лучший отрезок длины k. Задача КТП: наибольшая сумма и среднее, LeetCode 643, счётчик в окне.
  4. 9.5 События во временном окне. Задача КТП: наибольшее число событий за любые N секунд.
  5. 9.6 Границы. k = 0, k = 1, k = n, k больше n и неверный k — тесты из контроля КТП.
  6. 9.7 Замер. Пересчёт окна против суммы каждого среза на списках разной длины.
  7. 9.8 Задача целиком. LeetCode 1423 от условия до проверки в порядке interview canvas, с ориентиром по минутам.
  8. 9.9 Ошибки и объяснение решения. Сводка ошибок модуля по симптомам и что говорить интервьюеру.
  9. 9.10 Практика и ДЗ. Стартовый набор, тесты, домашнее задание.
  10. 9.11 Мок-интервью. Восемь задач на окно по этапам секции: вопросы, примеры, выбор техники, код с тестами, прогон, секундомер.

§9Проверьте себя

Вопрос 1Почему сдвиг окна стоит O(1), хотя в окне k элементов?

  • sum(a[l:l + k]) создаёт срез и складывает все k элементов, это O(k). Выигрыш даёт отказ от пересчёта всей суммы.

  • Верно. Один элемент уходит слева, один приходит справа, остальные k − 1 остаются. Сумму исправляют вычитанием и сложением.

  • В окно входят все k элементов, и все они входят в сумму. Но при сдвиге меняются только два из них.

Вопрос 2Сколько окон длины 4 в списке из 10 элементов?

  • Последнее окно начинается с индекса 6: a[6:10]. Окна, которое начиналось бы с индекса 7, нет — ему не хватает элементов.

  • Это n − k. Окна начинаются с индексов 0, 1, …, 6 — это семь значений.

  • Верно: n − k + 1 = 10 − 4 + 1. Правило «элементов n, окон длины k — n − k + 1» из занятия 7.

Вопрос 3Какая форма окна подходит для задачи «найти самую длинную подстроку без повторяющихся символов»?

  • Верно. Длина окна в условии не названа, она определяется требованием «без повторов». Это LeetCode 3, занятие 10.

  • Для каждого k нужен свой проход, всего O(n²). Окно переменной длины решает задачу за один проход.

  • Указатели навстречу сравнивают элементы с разных концов. Подстрока — это участок подряд, его проходят указатели в одну сторону.

Источники главы
  1. Журнал Яндекс Образования. Алгоритмические собеседования в Яндексе: как подготовиться и чего ожидать — education.yandex.ru/journal; цитаты сверены 07.10.2026
  2. LeetCode. LeetCode 75 — leetcode.com/studyplan/leetcode-75; состав раздела Sliding Window проверен по данным сайта 07.10.2026
  3. LeetCode. Top Interview 150 — leetcode.com/studyplan/top-interview-150; состав раздела и метки задач проверены 07.10.2026
  4. pandas. Series.rolling — pandas.pydata.org
  5. Документация Python. collections.deque — docs.python.org
  6. КТП ОП.04, занятия 9 и 10
Модуль 9 · Скользящее окно · ОП.04 · 3 курс Автор: Макаров Максим Николаевич