Что такое Big O

В этом уроке ты
  • Научишься оценивать программы асимптотической сложности: O(1), O(n).
  • Узнаешь, как применять Big O на практике.
  • Закрепишь знания, пройдя тест.
Оценка сложности

Оценка сложности — это способ понять, как долго будет работать программа и сколько памяти она будет потреблять в зависимости от размера входных данных.

Оценку сложности алгоритмов также могут называть асимптотической сложностью. Это одно и то же!

Благодаря оценке сложности можно даже без запуска программы понять, как много ресурсов, в зависимости от входных данных, потребляет программа.

Big O нотация

Big O показывает верхнюю границу сложности алгоритма — то есть максимально возможное потребление ресурсов. Обычно в Big O оценивают время и память. Примеры Big O оценки: O(1), O(n), O(n*n) и т.д.

Big O — это промышленный стандарт. Когда на собеседовании или в работе просят оценить сложность алгоритма, обычно имеют в виду именно Big O.

На алгоритмическом собеседовании без оценки алгоритма в Big O нотации зачастую кандидату даже не дают написать код. В общем, это база!
Оцениваем программу в Big O

Теперь посмотрим на несколько программ с популярными оценками в Big O. Твоя задача — взглянуть на примеры и разобраться, почему у них именно такая асимптотическая оценка.

Дальше по курсу мы подробно разберем каждую из оценок сложности. А пока попробуй интуитивно понять почему такая оценка сложности.
Программа 1
// Время: O(1)
// Память: O(1)

public class Solution {
    public bool IsZero(List<int> nums, int i) {
        bool result = false;
        if (nums[i] == 0) {
            result = true;
        }
        return result;
    }
}

Функция is_zero всегда выполняет одно и то же количество операций и использует одно и то же количество памяти — независимо от того, насколько большой массив nums и какое значение i. Это и есть признак константной сложности: O(1).

Программа 2
// Время: O(n), где n - размер массива nums
// Память: O(n), где n - размер массива nums

// Если nums=[1,2,3,4], то результат [4,3,2,1]
// Если nums=[1,2,3,4,5], то результат [5,4,3,2,1]

public class Solution {
    public List<int> ReverseNums(List<int> nums) {
        List<int> result = new List<int>();
        for (int i = nums.Count - 1; i >= 0; i--) {
            result.Add(nums[i]);
        }
        return result;
    }
}
  • Время: O(n), потому что мы один раз проходим по всему массиву nums.
  • Память: O(n), потому что мы создаём новый массив result такого же размера, как nums.
Программа 3
// Время: O(n), где n — размер массива nums
// Память: O(1)

// Если nums=[1,2,3,4], результат будет [4,3,2,1]
// Если nums=[1,2,3,4,5], результат будет [5,4,3,2,1]

public class Solution {
    public static List<int> ReverseNums(List<int> nums) {
        int p1 = 0;
        int p2 = nums.Count - 1;
        while (p1 < p2) {
            int temp = nums[p1];
            nums[p1] = nums[p2];
            nums[p2] = temp;
            p1 += 1;
            p2 -= 1;
        }
        return nums;
    }
}

В этом случае мы не создаём новый массив, поэтому память O(1). А время всё так же O(n), ведь нужно один раз пробежаться по массиву.

Про основную задачу Big O

Big O нотацию чаще всего используют, чтобы сравнить несколько решений одной задачи, а не чтобы померить конкретное время работы. Big O лишь косвенно связано с фактическим временем исполнения. Из-за этого и возникают распространённые заблуждения.

Главная задача Big O — показать, как изменятся затраты по времени и памяти, если увеличить объем данных в 10, 100 или 1000 раз и более. Big O не предназначена для точного измерения времени исполнения.
Что дальше

Переходи к следующему уроку, чтобы узнать о хитрых случаях оценки Big O и ещё больше прокачать навыки анализа кода!