Перейти к основному содержимому

Big O для памяти

Big O может описывать память так же, как и время: сколько дополнительного места нужно алгоритму при росте входных данных?

Мы считаем только дополнительное место — переменные и списки, которые создаёт алгоритм, — а не сами входные данные. Это дополнительное место называется вспомогательной памятью.

O(1) по памяти: фиксированное количество переменных независимо от входных данных. O(n) по памяти: для каждого входного элемента сохраняется что-то новое, например копия или множество уже встреченных значений.


O(1) по памяти

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

Суммирование, поиск максимума и линейный поиск — все они работают за O(n) по времени, но O(1) по памяти: они читают много, а запоминают почти ничего.

Сумма с одной переменной

Весь алгоритм запоминает ровно одно число — total. Расход памяти не растёт вместе со списком: O(1) по памяти.

Prompt
Напишите программу на Python, которая суммирует список 3, 1, 4, 1, 5, 9, 2, 6 с помощью одной дополнительной переменной и выводит сумму, чтобы показать алгоритм с O(n) по времени, но O(1) по памяти.
Вывод: полная программа на Python
Sum with one variable

O(n) по памяти

Как только алгоритм строит что-то с одной записью на каждый входной элемент — новый список, словарь, — его пространственная сложность становится O(n): вдвое больше входных данных — вдвое больше памяти.

Само по себе это не плохо. Это просто цена, которую стоит замечать, потому что ею можно обменяться.

Построение нового списка

Выходной список получает по одному элементу на каждый входной элемент. 5 на входе, 5 на выходе — память растёт вместе с входными данными: O(n) по памяти.

Prompt
Напишите программу на Python, которая строит новый список, в котором каждый элемент списка 1, 2, 3, 4, 5 удвоен, добавляя элементы в пустой список в цикле, а затем выводит входной и выходной списки.
Вывод: полная программа на Python
Build a new list

Обмен памяти на время

Часто можно потратить память, чтобы сэкономить время. Классический пример — Two Sum (сумма двух): найти в списке два числа, которые в сумме дают целевое значение.

Прямой способ проверяет каждую пару — O(n²) по времени, O(1) по памяти. Быстрый способ проходит по списку один раз и запоминает каждое встреченное число во множестве. Для каждого числа он спрашивает: «встречал ли я уже target - n?» — O(n) по времени, O(n) по памяти.

Обычно такой обмен того стоит: память в машину можно добавить, а время — нельзя.

Two Sum с двумя циклами

Проверяется каждая пара, пока не найдётся совпадение, — до 15 проверок для 6 элементов, и количество проверок растёт как квадрат размера входных данных. Дополнительная память не используется.

Prompt
Напишите программу на Python, которая находит в списке 2, 11, 15, 1, 8, 7 два числа, дающих в сумме 9, проверяя каждую пару с помощью двух вложенных циклов и подсчитывая проверки. Выведите каждое совпадение вместе с количеством проверок на данный момент, а в конце выведите общее количество проверок.
Вывод: полная программа на Python
Two Sum with two loops

Two Sum с множеством

Один проход, 6 проверок. Каждое число ищется и сохраняется во множестве seen — работа за постоянное время на каждый элемент. Множество — это та память O(n), которая покупает время O(n).

Prompt
Напишите программу на Python, которая за один проход находит в списке 2, 11, 15, 1, 8, 7 два числа, дающих в сумме 9: храните множество уже встреченных чисел и для каждого числа проверяйте, встречалась ли уже разность целевого значения и этого числа. Выведите каждое совпадение, а в конце выведите, что каждый элемент был проверен один раз.
Вывод: полная программа на Python
Two Sum with a set