Алгоритмы на массивах · модуль 9 · скользящее окно
Глава 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 75 | 643, 1456, 1004, 1493 | Первые две задачи — окно фиксированной длины, две следующие — переменной |
| LeetCode · Top Interview 150 | 209, 3, 30, 76 | Все четыре — окно переменной длины, занятие 10 |
Раздел LeetCode 75 начинается с окна фиксированной длины: на нём проще всего увидеть, как сумма окна пересчитывается при сдвиге. Задачи на окно переменной длины используют тот же сдвиг, но длина окна в них меняется по условию.
§3Задачи с собеседований
У всех задач ниже на LeetCode стоит метка Sliding Window, это проверено по данным сайта. Первые шесть — окно фиксированной длины, остальные используют окно вместе с техниками из следующих занятий.
| Номер и название | Сложность | Что нужно сделать | Где в курсе |
|---|---|---|---|
| 643 · Maximum Average Subarray I | Easy | Найти отрезок длины k с наибольшим средним | Модуль 9, лучший отрезок длины k |
| 1456 · Maximum Number of Vowels in a Substring of Given Length | Medium | Найти подстроку длины k, в которой больше всего гласных | Модуль 9, счётчик в окне |
| 1343 · Number of Sub-arrays of Size K and Average Greater than or Equal to Threshold | Medium | Посчитать отрезки длины k со средним не меньше порога | Модуль 9 |
| 2379 · Minimum Recolors to Get K Consecutive Black Blocks | Easy | Найти отрезок длины k, где меньше всего белых клеток | Модуль 9 |
| 1052 · Grumpy Bookstore Owner | Medium | Выбрать отрезок из k минут, который даёт больше всего довольных покупателей | Модуль 9 |
| 2090 · K Radius Subarray Averages | Medium | Для каждого элемента найти среднее окна радиуса k вокруг него | Модуль 9 |
| 219 · Contains Duplicate II | Easy | Проверить, есть ли два равных элемента на расстоянии не больше k | Окно и множество, занятие 19 |
| 438 · Find All Anagrams in a String | Medium | Найти все подстроки, которые являются перестановкой образца | Окно и частотный словарь, занятие 18 |
| 239 · Sliding Window Maximum | Hard | Для каждого окна длины k найти максимум | Окно и дек, занятие 25 |
| 209 · Minimum Size Subarray Sum | Medium | Найти самый короткий отрезок с суммой не меньше S | Окно переменной длины, занятие 10 |
| 3 · Longest Substring Without Repeating Characters | Medium | Найти самую длинную подстроку без повторов | Окно переменной длины, занятие 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: для них трёх значений ещё нет.
>>> 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]
>>> 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 элементов для первого окна и по два для каждого следующего.
| n | k | Пересчёт с нуля: (n − k + 1)·k | Сдвиг окна: k + 2·(n − k) |
|---|---|---|---|
| 7 | 3 | 15 | 11 |
| 100 000 | 100 | 9 990 100 | 199 900 |
| 1 000 000 | 1 000 | 999 001 000 | 1 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, 1456 | LeetCode 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 — тренажёр в формате собеседования.
- 9.2 Формулировки и вопросы до решения. Как звучат задачи на окно фиксированной длины и что уточнить до кода.
- 9.3 Окно и пересчёт за O(1). Сумма каждого среза против сдвига окна, состояние окна, пошаговый прогон.
- 9.4 Лучший отрезок длины k. Задача КТП: наибольшая сумма и среднее, LeetCode 643, счётчик в окне.
- 9.5 События во временном окне. Задача КТП: наибольшее число событий за любые N секунд.
- 9.6 Границы. k = 0, k = 1, k = n, k больше n и неверный k — тесты из контроля КТП.
- 9.7 Замер. Пересчёт окна против суммы каждого среза на списках разной длины.
- 9.8 Задача целиком. LeetCode 1423 от условия до проверки в порядке interview canvas, с ориентиром по минутам.
- 9.9 Ошибки и объяснение решения. Сводка ошибок модуля по симптомам и что говорить интервьюеру.
- 9.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²). Окно переменной длины решает задачу за один проход.
Указатели навстречу сравнивают элементы с разных концов. Подстрока — это участок подряд, его проходят указатели в одну сторону.
- Журнал Яндекс Образования. Алгоритмические собеседования в Яндексе: как подготовиться и чего ожидать — education.yandex.ru/journal; цитаты сверены 07.10.2026
- LeetCode. LeetCode 75 — leetcode.com/studyplan/leetcode-75; состав раздела Sliding Window проверен по данным сайта 07.10.2026
- LeetCode. Top Interview 150 — leetcode.com/studyplan/top-interview-150; состав раздела и метки задач проверены 07.10.2026
- pandas. Series.rolling — pandas.pydata.org
- Документация Python. collections.deque — docs.python.org
- КТП ОП.04, занятия 9 и 10