Как преобразовать алгоритм с линейной сложностью O(n) в логарифмическую O(log n)?

«Как преобразовать алгоритм с линейной сложностью O(n) в логарифмическую O(log n)?» — вопрос из категории Алгоритмы и структуры данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Да, это возможно, если заменить алгоритм полного перебора на алгоритм, использующий стратегию "разделяй и властвуй" или двоичный поиск.

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

Пример: Линейный поиск vs Бинарный поиск

  • Линейный поиск (O(n)):

    int linearSearch(int[] arr, int target) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) return i;
        }
        return -1;
    }
  • Бинарный поиск (O(log n)):

    int binarySearch(int[] arr, int target) {
        int left = 0, right = arr.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2; // Предотвращает переполнение
            if (arr[mid] == target) return mid;
            if (arr[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        return -1;
    }

Другие подходы:

  • Использование структур данных с логарифмическим доступом: TreeMap, TreeSet.
  • Алгоритмы типа "разделяй и властвуй": быстрая сортировка (O(n log n)), поиск в сбалансированном двоичном дереве поиска (BST).

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