O(√n) — Сложность корень из n

Определение

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

Формула

где — размер входных данных

Характеристики

  • Эффективнее чем O(n), но медленнее чем O(log n)
  • Часто встречается в задачах с числами
  • Типична для оптимизированных алгоритмов перебора
  • Хороший компромисс между скоростью и простотой

Визуализация проверки делителей

Проверка делителей числа 100:

Полный перебор O(n):
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, ..., 100
└─────────────────────────────────────┘
            100 операций

Оптимизированный O(√n):
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
└──────────────────────────┘
      10 операций = √100

Парные делители:
1 × 100 = 100
2 × 50 = 100
4 × 25 = 100
5 × 20 = 100
10 × 10 = 100  <- граница √100

Сравнение производительности

Размер (n)√nlog₂ nn
103310
100107100
1,00032101,000
10,0001001310,000
1,000,0001,000201,000,000

График сложности

Операции
     |
1000 |                                  ●     O(n)
     |                                ●
 750 |                              ●
     |                            ●
 500 |                          ●
     |                        ●
 250 |                      ●     O(√n)
     |                 ● ●
 100 |          ● ● ●
     |    ● ● ●  O(log n)
  10 | ●●●
     |
   0 +---------------------------------------------->
     10    100     1K     10K    100K    1M      n

Математическое обоснование

Для проверки делителей числа n:

Если d — делитель n, то n = d × k

Если d > √n, то k < √n

Значит, для каждого делителя > √n существует парный делитель < √n

Вывод: Достаточно проверить только числа до √n!

Практическое применение

  • Проверка простоты чисел
  • Факторизация
  • Поиск делителей
  • Jump Search (поиск прыжками)
  • Алгоритмы работы с числами
  • Оптимизация переборных алгоритмов

Сравнение с другими алгоритмами поиска

АлгоритмСложностьТребования
Линейный поискO(n)Нет
Jump SearchO(√n)Отсортированный массив
Бинарный поискO(log n)Отсортированный массив

Важно помнить

✅ Эффективнее линейного поиска ✅ Часто оптимальна для задач с числами ✅ Простая реализация ✅ Хороший компромисс между O(log n) и O(n) ❌ Медленнее логарифмической сложности ❌ Не всегда применима

Примеры кода

1. Проверка простоты числа

function isPrime(n) {
  if (n <= 1) return false;
  if (n <= 3) return true;
  if (n % 2 === 0 || n % 3 === 0) return false;
 
  // Проверяем делители только до √n
  for (let i = 5; i * i <= n; i += 6) {
    if (n % i === 0 || n % (i + 2) === 0) {
      return false;
    }
  }
 
  return true;
}
 
console.log(isPrime(17)); // true
console.log(isPrime(100)); // false

2. Поиск делителей числа

function findDivisors(n) {
  const divisors = [];
 
  // Проверяем только до √n
  for (let i = 1; i * i <= n; i++) {
    if (n % i === 0) {
      divisors.push(i);
      // Добавляем парный делитель
      if (i !== n / i) {
        divisors.push(n / i);
      }
    }
  }
 
  return divisors.sort((a, b) => a - b);
}
 
console.log(findDivisors(36)); // [1, 2, 3, 4, 6, 9, 12, 18, 36]

3. Решето Эратосфена (оптимизированное)

function sieveOfEratosthenes(n) {
  const isPrime = new Array(n + 1).fill(true);
  isPrime[0] = isPrime[1] = false;
 
  // Проверяем только до √n
  for (let i = 2; i * i <= n; i++) {
    if (isPrime[i]) {
      // Вычеркиваем все кратные i
      for (let j = i * i; j <= n; j += i) {
        isPrime[j] = false;
      }
    }
  }
 
  return isPrime.map((prime, num) => prime ? num : null).filter(x => x !== null);
}
 
console.log(sieveOfEratosthenes(30));
// [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
function jumpSearch(arr, target) {
  const n = arr.length;
  const step = Math.floor(Math.sqrt(n));
  let jump = step;
  let prev = 0;
 
  // Прыгаем блоками по √n
  while (arr[Math.min(jump, n) - 1] < target) {
    prev = jump;
    jump += step;
    if (prev >= n) return -1;
  }
 
  // Линейный поиск в найденном блоке
  while (arr[prev] < target) {
    prev++;
    if (prev === Math.min(jump, n)) return -1;
  }
 
  if (arr[prev] === target) return prev;
  return -1;
}
 
const arr = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19];
console.log(jumpSearch(arr, 13)); // 6

5. Факторизация числа

function primeFactorization(n) {
  const factors = [];
 
  // Проверяем делители до √n
  for (let i = 2; i * i <= n; i++) {
    while (n % i === 0) {
      factors.push(i);
      n = Math.floor(n / i);
    }
  }
 
  // Если осталось число > 1, оно простое
  if (n > 1) {
    factors.push(n);
  }
 
  return factors;
}
 
console.log(primeFactorization(84)); // [2, 2, 3, 7]
console.log(primeFactorization(100)); // [2, 2, 5, 5]