Алгоритмы и сложность: тренировочные вопросы с объяснениями

Бесплатные тестовые вопросы по теме Алгоритмы и сложность с подсказками и объяснениями, трёх уровней: ключевые термины и факты, применение понятий, кейсы и анализ.

Бесплатная задачаЛёгкая

Какой класс сложности растёт быстрее всех при больших n?

Следующая задача →

Что вы отрабатываете

  1. Лёгкаяключевые термины и факты
  2. Средняяприменение понятий
  3. Сложнаякейсы и анализ

Изучите тему «Алгоритмы и сложность» с нуля

1Что измеряет сложность

Алгоритм — это конечный список точных шагов, решающих задачу, например сортировку списка или поиск имени в телефонной книге.

Два алгоритма могут решать одну и ту же задачу, но тратить очень разное время. Сложность описывает, как объём работы растёт при увеличении входных данных.

Размер входных данных обозначают n: число элементов для сортировки, длина списка, число вершин графа.

Представьте поиск имени в телефонной книге на 1000 страниц. Чтение каждой страницы займёт до 1000 шагов. Если открывать книгу посередине и каждый раз делить её пополам, понадобится около 10 шагов.

Временная сложность считает шаги. Пространственная сложность считает дополнительную память. Обе записываются как функция от n.

Обычно рассматривают худший случай: наибольший объём работы среди всех входов размера n. Иногда спрашивают средний или лучший случай.

Самопроверка Алгоритм, у которого объём работы растёт как n², выполняется за 1 секунду при n = 1000. Сколько времени он займёт примерно при n = 2000?
  1. 1 секунду
  2. 2 секунды
  3. 4 секунды
  4. 8 секунд

Ответ: 4 секунды. При удвоении n значение n² умножается на 2² = 4, поэтому время вырастет примерно с 1 до 4 секунд. 2 секунды были бы ответом для линейного роста, а 8 — для n³.

2Big O и классы роста

Запись Big O сохраняет только то, что важно при больших n. Постоянные множители отбрасывают и оставляют лишь самое быстрорастущее слагаемое.

3n² + 5n + 2 ⇒ O(n²)

При n = 1000 слагаемое n² равно 3 000 000, а 5n — всего 5000. Меньшие слагаемые почти не влияют на сумму.

Эти классы встречаются снова и снова, от самого медленного роста к самому быстрому:

  • O(1), константа: чтение элемента массива по индексу.
  • O(log n), логарифмическая: двоичный поиск, который на каждом шаге уменьшает задачу вдвое.
  • O(n), линейная: один проход по всем элементам, например поиск наибольшего значения.
  • O(n log n): хорошие алгоритмы сортировки, например сортировка слиянием.
  • O(n²), квадратичная: два вложенных цикла по элементам, например пузырьковая сортировка.
  • O(2ⁿ), экспоненциальная: перебор всех подмножеств. Быстро становится непригодной.
ntlog nnn log nn²2ⁿ

Big O — это верхняя оценка: объём работы растёт не быстрее этого. Ω (Big Omega) — нижняя оценка, а Θ (Theta) — точная оценка, одновременно верхняя и нижняя.

Основание логарифма в Big O не важно, потому что логарифмы с разными основаниями отличаются лишь постоянным множителем.

Самопроверка Чему равна Big O для 4n + 2n² + 100?
  1. O(100)
  2. O(2n²)
  3. O(n)
  4. O(n²)

Ответ: O(n²). При больших n доминирует слагаемое n², а постоянный множитель 2 отбрасывается. O(n) сохраняет не то слагаемое, а O(2n²) забывает отбросить константу.

3Поиск, сортировка и рекурсия

Несколько алгоритмов встречаются почти в каждом курсе. Выучите их сложности как факты.

  • Линейный поиск проверяет элементы один за другим: O(n). Двоичный поиск требует отсортированного массива и на каждом шаге делит диапазон пополам: O(log n).
  • Сортировки пузырьком, вставками и выбором сравнивают и меняют элементы местами во вложенных циклах: O(n²). Сортировка вставками работает за O(n) на уже отсортированном массиве.
  • Сортировка слиянием делит массив пополам, сортирует части и сливает их: O(n log n) в любом случае, с O(n) дополнительной памяти.
  • Быстрая сортировка разбивает массив вокруг опорного элемента: в среднем O(n log n), но в худшем случае O(n²), например для отсортированного массива, если опорным взят первый элемент.
  • Никакая сортировка, основанная только на сравнении элементов, не может превзойти Ω(n log n) в худшем случае. Сортировка подсчётом быстрее, потому что не сравнивает.

Рекурсивная функция вызывает саму себя для меньшего входа, пока не дойдёт до базового случая, на который отвечает напрямую. Время её работы записывают в виде рекуррентного соотношения:

  • T(n) = T(n/2) + O(1) даёт O(log n), как двоичный поиск.
  • T(n) = 2T(n/2) + O(n) даёт O(n log n), как сортировка слиянием.
  • T(n) = T(n − 1) + O(n) даёт O(n²).
  • T(n) = 2T(n − 1) + O(1) даёт O(2ⁿ).

Стоит знать три идеи построения алгоритмов. Разделяй и властвуй делит задачу, решает части и объединяет результаты. Жадный подход на каждом шаге выбирает локально лучший вариант. Динамическое программирование запоминает ответы на перекрывающиеся подзадачи, чтобы вычислять их один раз.

Самопроверка Какова временная сложность быстрой сортировки в худшем случае?
  1. O(log n)
  2. O(n log n)
  3. O(n)
  4. O(n²)

Ответ: O(n²). При плохих опорных элементах каждое разбиение оставляет n − 1 элементов по одну сторону, что даёт O(n²). O(n log n) — это её средний случай и худший случай сортировки слиянием.

4Метод по шагам

Чтобы найти временную сложность фрагмента кода:

  1. Определите, что такое n: размер входных данных.
  2. Посчитайте, сколько раз выполняется каждый цикл. Цикл, который каждый раз прибавляет 1, выполняется около n раз. Цикл, который удваивает или делит пополам, выполняется около log₂ n раз.
  3. Вложенные циклы перемножаются. Циклы, идущие один за другим, складываются.
  4. Для рекурсивной функции запишите рекуррентное соотношение: сколько вызовов, какого размера, плюс работа на каждый вызов.
  5. Оставьте самое быстрорастущее слагаемое и отбросьте константы.
  6. Проверьте на небольшом числе, например n = 8 или n = 1024.

В теоретическом вопросе сначала назовите алгоритм или идею, о которой речь, затем вспомните его сложность и условия применения (отсортированные данные, неотрицательные веса, перекрывающиеся подзадачи).

5Разобранный пример

Пройдите каждый шаг. Попробуйте предсказать следующий, прежде чем открыть его.

Разобранный пример

Какова временная сложность этого кода? for i = 1 to n: (j = 1; while j < n: j = j × 2)

1

Назовите размер входных данных

n — это число, до которого работают циклы.

2

Посчитайте внешний цикл

i изменяется от 1 до n с шагом 1, поэтому внешний цикл выполняется n раз.

3

Посчитайте внутренний цикл

j принимает значения 1, 2, 4, 8, … и останавливается, достигнув n. После k витков j = 2k, поэтому цикл остановится примерно через log₂ n витков.

4

Объедините циклы

Внутренний цикл находится внутри внешнего, поэтому количества перемножаются.

n · log₂ n ⇒ O(n log n)
5

Проверьте на числе

При n = 1024 внутренний цикл выполняется log₂ 1024 = 10 раз, поэтому тело выполняется 1024 · 10 = 10 240 раз. Это намного меньше, чем n² = 1 048 576.

Ответ

O(n log n)

6Типичные ошибки

  • Перемножать циклы, идущие один за другим. n + n = 2n — это по-прежнему O(n).
  • Сохранять константы, как в O(2n) или O(n/2). Обе записи равны O(n).
  • Считать цикл с удвоением за n витков. Он выполняется около log₂ n раз.
  • Применять двоичный поиск к неотсортированным данным или к связному списку, в котором середина недостижима за один шаг.
  • Приводить средний случай быстрой сортировки, когда спрашивают худший.
  • Думать, что Big O означает «точно». O(n²) — это верхняя оценка; Θ(n²) — точный рост.
Самопроверка Функция выполняет цикл из n итераций, а затем, отдельно, ещё один цикл из n итераций. Какова её временная сложность?
  1. O(2n)
  2. O(log n)
  3. O(n)
  4. O(n²)

Ответ: O(n). Циклы, идущие один за другим, складываются: n + n = 2n, а константа отбрасывается, поэтому получается O(n). O(n²) было бы верно, только если бы один цикл находился внутри другого.

7Как выглядят экзаменационные задачи

  • Лёгкая: ключевые термины и факты. Сложность двоичного поиска, сортировки слиянием или доступа к элементу массива, смысл O, Ω и Θ, что такое рекурсия.
  • Средняя: применение понятий. Сложность фрагмента кода, решение рекуррентного соотношения, как меняется время при удвоении n, какой алгоритм подходит для задачи.
  • Сложная: случаи и анализ. Основная теорема о рекуррентных соотношениях, худшие случаи быстрой сортировки, жадный подход и динамическое программирование, классы P, NP и NP-полные.

P содержит задачи, которые можно решить за полиномиальное время. NP содержит задачи, решения которых можно проверить за полиномиальное время. Каждая задача из P входит в NP; равно ли P = NP, до сих пор неизвестно.

Изучайте шаг за шагом в приложенииИзучайте шаг за шагом в приложении

Примеры вопросов

Пример 1Лёгкая

Какая нотация описывает верхнюю границу роста?

  1. AОмега-большое
  2. BОмега-малое
  3. CO-большое
  4. DТета-большое
Показать подсказки
  1. «Не более чем».
  2. Два неверных ответа теперь зачёркнуты. Один из двух оставшихся верный.
Показать ответ и объяснение

Почему это ответ

O задаёт верхнюю границу, Ω — нижнюю, а Θ — точную (асимптотически точную) границу.

Ответ

C · O-большое
Пример 2Средняя

В отсортированном массиве вы ищете два элемента с заданной суммой, двигая по одному указателю с каждого конца внутрь. Какова временна́я сложность?

  1. AO(n)
  2. BO(n log n)
  3. CO(n²)
  4. DO(log n)
Показать подсказки
  1. Каждый шаг сдвигает один указатель на одну позицию.
  2. Два неверных ответа теперь зачёркнуты. Один из двух оставшихся верный.
Показать ответ и объяснение

Почему это ответ

Если сумма слишком мала, левый указатель сдвигается вправо, если слишком велика — правый влево, поэтому шагов не больше n.

Ответ

A · O(n)
Пример 3Сложная

Алгоритм Штрассена умножает матрицы, используя 7 вместо 8 рекурсивных умножений блоков половинного размера. Каково время его работы?

  1. AΘ(n² log n)
  2. BΘ(n2)
  3. CΘ(n³)
  4. DΘ(nlog₂ 7), примерно n2,81
Показать подсказки
  1. Рекуррентное соотношение T(n) = 7T(n/2) + O(n²).
  2. Два неверных ответа теперь зачёркнуты. Один из двух оставшихся верный.
Показать ответ и объяснение

Почему это ответ

При a = 7 и b = 2 член nlog₂ 7 доминирует над работой сложения O(n²), что даёт примерно n2,81.

Ответ

D · Θ(nlog₂ 7), примерно n2,81

Вопросы и ответы

Алгоритмы и сложность: что это?

Два алгоритма могут решать одну и ту же задачу, но тратить очень разное время. Сложность описывает, как объём работы растёт при увеличении входных данных.

Размер входных данных обозначают n: число элементов для сортировки, длина списка, число вершин графа.

Алгоритмы и сложность: как изучить шаг за шагом?
  1. Что измеряет сложность
  2. Big O и классы роста
  3. Поиск, сортировка и рекурсия
  4. Метод по шагам
  5. Разобранный пример
  6. Типичные ошибки
  7. Как выглядят экзаменационные задачи
Алгоритмы и сложность: что вы тренируете?
  • Лёгкая: ключевые термины и факты
  • Средняя: применение понятий
  • Сложная: кейсы и анализ

У каждого вопроса четыре варианта ответа, и только один правильный. Застряли? Сначала откройте небольшую подсказку, а полное объяснение — только когда оно понадобится.

Как проходят занятия

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

Темы до и после этой

Далее

Курсы с этой темой

Другие темы: Информатика

Лист заданий для печати