Бесплатная бета: 60 дней полного доступа, без карты.мест осталось: 84Зарегистрироваться бесплатно

Мы используем необходимые куки для работы сайта (вход и язык). Если ты согласишься, мы также загрузим Google Analytics, чтобы видеть, какие страницы читают, и Google reCAPTCHA для защиты форм обратной связи и сообщений об ошибке от спама. Политика конфиденциальности

Все паттерны

Монотонная дек-очередь (максимум/минимум окна)

Monotonic deque (sliding window max/min)

O(n)

Дек, упорядоченный так, что спереди всегда лежит максимум окна. Проигравшие значения уходят сзади, а устаревшие спереди.

Обновлено 17 окт. 2026 г.

Монотонная дек-очередь (максимум/минимум окна): как это работает?

Дек хранит индексы, а не значения. Индекс говорит, когда элемент выйдет из окна.

Перед вставкой нового индекса снимите сзади все индексы с меньшим значением. Они уже никогда не станут максимумом.

Положите новый индекс в конец. Значения теперь убывают от начала к концу.

Посмотрите на передний индекс. Если он выехал из окна, уберите его.

Теперь спереди лежит максимум окна. Читайте его без всякого перебора.

Каждый индекс кладётся один раз и снимается один раз. Именно это держит проход линейным.

Источники: Википедия: Двухсторонняя очередь, Документация Python (англ.): collections.deque

  1. дек = [0]Окно из 3 по массиву [1, 3, -1, -3, 5]. Индекс 0 входит.
  2. дек = [1]Тройка бьёт стоящую сзади единицу. Индекс 0 снимается с конца.
  3. дек = [1, 2]-1 меньше, поэтому остаётся. Окно заполнено, максимум равен 3.
  4. дек = [1, 2, 3]-3 снова меньше. Передний индекс всё ещё в окне.
  5. дек = [4]Пятёрка бьёт всех и опустошает дек. Максимум равен 5.
Максимум в каждом окне из 3 чисел
maxSlidingWindow([1, 3, -1, -3, 5, 3, 6, 7], 3)
nums
1
3
-1
-3
5
3
6
7
deque (индекс:значение, начало слева, значения убывают к концу)
пусто
result
пусто

Ищем максимум в каждом окне из 3 чисел. В деке лежат индексы, чьи значения ещё могут стать максимумом.

Гонка скорости
Максимум каждых 10 подряд идущих значений в одних и тех же 40 числах

Столбики: 40 значений. Окно длиной 10, это четверть массива, и таблица ниже сохраняет эту долю.

Одна операция: одно сравнение двух значений. За каждый кадр все дорожки делают одинаковое число операций, поэтому медленная отстаёт.

Повторный просмотр каждого окна O(n·k)
операций: 0
Монотонный дек O(n)
операций: 0

 

А если чисел больше

Операции для n чисел и примерное время при 100 миллионах простых операций в секунду. Это оценка по тому же счёту, а не замер.

n = 1 000
Повторный просмотр каждого окна187 тыс. · 1,9 мс
Монотонный дек1,7 тыс. · меньше 1 мс
n = 100 000
Повторный просмотр каждого окна1,9 млрд · 19 с
Монотонный дек170 тыс. · 1,7 мс
n = 10 000 000
Повторный просмотр каждого окна18,7 трлн · 2,2 дн.
Монотонный дек17 млн · 170 мс

Монотонная дек-очередь (максимум/минимум окна): шаблон кода

function maxSlidingWindow(nums, k) {
    const deque = []; // stores indices, values decreasing
    const result = [];
    for (let i = 0; i < nums.length; i++) {
        while (deque.length && deque[0] <= i - k) deque.shift();
        while (deque.length && nums[deque[deque.length - 1]] < nums[i]) deque.pop();
        deque.push(i);
        if (i >= k - 1) result.push(nums[deque[0]]);
    }
    return result;
}

Монотонная дек-очередь (максимум/минимум окна): разбор примера

Самый длинный отрезок в пределах лимита

Найдите самый длинный отрезок, где наибольшее и наименьшее значения различаются не больше чем на лимит.

Отрезок должен быть непрерывным.

Растите переменное окно и держите два дека: для максимумов и для минимумов.

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

function longestSubarray(nums, limit) {
    const maxQ = []; // indices, values falling from front to back
    const minQ = []; // indices, values rising from front to back
    let left = 0;
    let best = 0;

    for (let right = 0; right < nums.length; right++) {
        while (maxQ.length && nums[maxQ[maxQ.length - 1]] <= nums[right]) maxQ.pop();
        while (minQ.length && nums[minQ[minQ.length - 1]] >= nums[right]) minQ.pop();
        maxQ.push(right);
        minQ.push(right);

        while (nums[maxQ[0]] - nums[minQ[0]] > limit) {
            if (maxQ[0] === left) maxQ.shift();
            if (minQ[0] === left) minQ.shift();
            left++;
        }

        best = Math.max(best, right - left + 1);
    }

    return best;
}

Монотонная дек-очередь (максимум/минимум окна): когда применять?

Паттерн «Монотонная дек-очередь (максимум/минимум окна)» нужен, когда в условии есть слова «максимум или минимум каждого окна размера k», «максимум/минимум скользящего окна» или «кратчайший подмассив с суммой не менее K». Решение на нём обычно укладывается в O(n).

  • максимум или минимум каждого окна размера k
  • максимум/минимум скользящего окна
  • кратчайший подмассив с суммой не менее K
  • нужно снимать/класть с обоих концов очереди
  • дек, двусторонняя очередь

Слова в условии для всех паттернов собраны в одной таблице: шпаргалка по паттернам алгоритмов.

Монотонная дек-очередь (максимум/минимум окна): с чем путают?

Паттерн «Монотонная дек-очередь (максимум/минимум окна)» чаще всего путают с этими паттернами: Монотонный стек, Скользящее окно (фиксированный размер), Бинарная куча / очередь с приоритетом и Стек (LIFO).

Монотонная дек-очередь (максимум/минимум окна): частые ошибки

  • Хранят значения вместо индексов

    Без индекса не понять, когда элемент устарел. Кладите позицию и читайте значение по ней.

  • Подрезают перед вставкой не тот конец

    Порядок здесь важен. Сначала снимите проигравших сзади, потом проверьте начало.

  • Небрежно обходятся с равными значениями

    Снимать ли при равенстве, решает, какой из дубликатов выживет. Это важно, когда ответ это индекс.

  • Берут кучу вместо дека

    Куча не умеет удалить элемент, только что вышедший из окна. Её удаления ленивые и стоят лишнего.

Паттерн «Монотонная дек-очередь (максимум/минимум окна)» решает такие задачи с собеседований: Максимум скользящего окна, Отрезок с разбросом в пределах лимита, Кратчайший подмассив с суммой не меньше k, Прыжки VI, Сумма подпоследовательности с ограничением, Максимум значения уравнения и Минимум скользящего окна.

  • Максимум скользящего окна: Чистая форма: читайте начало на каждом шаге.
  • Отрезок с разбросом в пределах лимита: Два дека, по одному на каждый край.
  • Кратчайший подмассив с суммой не меньше k: Префиксные суммы и возрастающий дек по ним.
  • Прыжки VI: Лучший результат внутри достижимого окна.
  • Сумма подпоследовательности с ограничением: То же окно, но по массиву динамики.
  • Максимум значения уравнения: Окно по x с ключом y минус x.
  • Минимум скользящего окна: Тот же код с перевёрнутым сравнением.

Монотонная дек-очередь (максимум/минимум окна): сложность по времени и памяти

У паттерна «Монотонная дек-очередь (максимум/минимум окна)» целевая сложность O(n).

n до 1e6 даёт O(n), ведь каждый индекс входит и выходит один раз. Память O(k) по размеру окна.

Где этот паттерн стоит в 150 шагах