Получить доступ

Что такое амортизированная сложность?

JuniorСложность алгоритмов
Ещё спрашивают так:
  • Почему добавление в динамический массив считается O(1), если иногда нужно копирование?
  • Чем амортизированная сложность отличается от средней?
Коротко

Амортизированная сложность — средняя стоимость операции в длинной серии: редкие дорогие операции «размазываются» по многим дешёвым.

  • Пример: добавление в динамический массив — обычно O(1), иногда копирование O(n), в среднем O(1)
  • Это гарантия на серию, а не вероятность: не путать со средним случаем по случайным данным

А ещё Ключ — массив растёт в разы (×2 или ×1,5), а не на фиксированное число

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Некоторые структуры данных иногда выполняют дорогую операцию, но так редко, что в сумме по серии стоимость на одну операцию остаётся маленькой.

Классический пример — динамический массив (list в Python, ArrayList в Java, vector в C++). Пока есть свободное место, добавление в конец — O(1). Когда место кончилось, выделяется массив вдвое больше и все элементы копируются — O(n). Посчитаем суммарную работу для n добавлений: копирования происходят при размерах 1, 2, 4, 8, …, n, их сумма меньше 2n. Плюс n простых вставок. Итого меньше 3n операций на n добавлений, то есть O(1) на операцию в среднем по серии.

Важно, что массив растёт в разы. Если бы он увеличивался на 10 элементов, копирований было бы n/10, каждое до n элементов — итого O(n²) на серию, O(n) на операцию.

Отличие от средней сложности: средняя считается по распределению входных данных (например, хеш-таблица при «хорошем» хеше). Амортизированная — это гарантия для любой последовательности операций, без вероятностей.

Другие примеры: расширение хеш-таблицы, очередь на двух стеках, система непересекающихся множеств (union-find).

Пример

import sys

a = []
prev = sys.getsizeof(a)
for i in range(20):
    a.append(i)
    size = sys.getsizeof(a)
    if size != prev:        # память выделяется скачками, а не на каждый append
        print(f"после {len(a)} элементов: {size} байт")
        prev = size

Что хотят услышать

  • Определение через стоимость серии операций.
  • Разбор динамического массива с подсчётом.
  • Почему рост должен быть в разы.
  • Отличие от средней сложности.

Частые ошибки

  • Говорить, что добавление в динамический массив «всегда O(1)».
  • Путать амортизированную сложность со средним случаем.

Что спросят дальше

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем