Важные нюансы Big O

В этом уроке ты
  • Познакомишься со всеми основными оценками сложности
  • Узнаешь самые частые оценки сложности по времени и памяти
  • Научишься оставлять в Big O оценке только действительно важные параметры
Основные оценки сложности

В ходе курса мы уже разобрали такие оценки сложности, как O(1), O(n) и O(n*n). Но также есть ещё несколько популярных оценок:

  • O(1) — константная
  • O(log(n)) — логарифмическая (разберём в следующих уроках)
  • O(n) — линейная
  • O(n*log(n)) — линейно-логарифмическая (разберём в следующих уроках)
  • O(n*n) — квадратичная
Если в оценке сложности для одной и той же переменной есть несколько слагаемых разных порядков, оставляют только самое “большое”.

Например, в O(n*log(n) + n*n) достаточно записать O(n*n).

Но в O(n + m*log(m)) ничего убирать нельзя, так как n и m — разные переменные.

Частота оценок сложности

У каждой алгоритмической темы есть типичные оценки сложности, поэтому важно обращать внимание на сложность отдельно для каждой темы. Однако в общем виде самые распространённые варианты можно свести к следующей таблице:

Оценка По времени По памяти
O(1) ОЧЕНЬ ЧАСТО ОЧЕНЬ ЧАСТО
O(log(n)) РЕДКО РЕДКО
O(n) ОЧЕНЬ ЧАСТО ОЧЕНЬ ЧАСТО
O(n*log(n)) РЕДКО ОЧЕНЬ РЕДКО
O(n*n) ЧАСТО РЕДКО
Зависимость от нескольких параметров
// Время: O(n+m), где n - размер nums1, m - размер nums2
// Память: O(n+m), где n - размер nums1, m - размер nums2
using System.Collections.Generic;

public class Solution {
    public List<int> MergeArrays(List<int> nums1, List<int> nums2) {
        List<int> result = new List<int>();
        foreach (int num in nums1) {
            result.Add(num);
        }
        foreach (int num in nums2) {
            result.Add(num);
        }
        return result;
    }
}

Здесь время и память зависят от двух параметров: n (размер nums1) и m (размер nums2). Поэтому асимптотика — O(n+m).

Можно обозначить размеры по-разному, например O(x+y). Важно лишь пояснить, что x и y — это размеры соответствующих массивов.

Ещё один способ оценить тот же код — сказать, что время и память равны O(n), если n — общее число элементов в обоих массивах. Но на практике часто предпочитают именно O(n+m), чтобы подчеркнуть, что у нас два независимых источника данных.

Незначительные аргументы
// Время: O(n), где n - размер nums
// Память: O(1)
using System.Collections.Generic;

public class Solution {
    public List<int> SetK(List<int> nums, int k) {
        for (int i = 0; i < nums.Count; i++) {
            nums[i] = k;
        }
        return nums;
    }
}

В функции присутствует параметр k, который не влияет на итоговую оценку сложности. Это нормально! Часто в алгоритме есть параметры, не меняющие асимптотику. Однако не забывай, что в других задачах дополнительные параметры могут влиять на сложность — проверяй каждый случай.

Главные выводы
  1. Есть пять наиболее частых оценок сложности: O(1), O(log(n)), O(n), O(n*log(n)) и O(n*n).
  2. Если для одной переменной встречаются несколько слагаемых разного порядка, оставляют только самое большое (например, n*n + n оценивается как O(n*n)).
  3. Оценка по времени и памяти может зависеть сразу от нескольких параметров, например O(n + m).
  4. Некоторые параметры могут не влиять на оценку сложности.