Массивы и O(n)

В этом уроке ты
  • Освоишь оценку сложности O(n) на примерах
  • Научишься распознавать линейную сложность по времени и памяти
  • Научишься оценивать время и память при работе с 2D массивами
Линейная сложность

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

Другими словами, если размер входных данных увеличится в 100 раз, то время и/или память алгоритма тоже вырастут примерно в 100 раз.

Когда встречается
- Линейная временная сложность чаще всего возникает, когда мы в цикле проходим по всему массиву.

- Линейная память обычно появляется, когда мы создаём дополнительный массив того же размера, что и исходный.
// Время: 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]
using System.Collections.Generic;

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.
Бонус: 2D массивы
// Время: O(n*m), где n - число строк, m - число столбцов
// Память: O(1)

public class Solution {
    public void PrintMatrix(List<List<int>> mat) {
        for (int i = 0; i < mat.Count; i++) {
            for (int j = 0; j < mat[i].Count; j++) {
                Console.WriteLine(mat[i][j]);
            }
        }
    }
}

При работе с двумерными массивами сложность часто оценивают исходя из общего числа элементов, которая вычисляется как n*m, где n — число строк, а m — число столбцов. При обходе всех элементов 2D-массива получаем оценку по времени O(n*m).

Сложность можно также записать как O(n), если n обозначает общее число элементов в массиве. Однако O(n*m) более предпочтительно, так как оно явно указывает на зависимость от числа строк и столбцов.

Самые частые оценки при работе с двумерными массивами это: O(n*m), O(n), O(m), O(1).

Главные выводы
  1. Если оценка кода по времени и памяти O(n) это значит, что при увеличении размера входных данных в 100 раз алгоритм увеличит потребляемую память и время исполнение примерно в 100 раз.
  2. При обходе двумерного массива сложность по времени оценивается как O(n*m).
  3. Линейная сложность – самая популярная асимптотическая оценка.
Что дальше

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