CP
Miscellaneous

Sieve of Eratosthenes

An ancient algorithm for finding all prime numbers up to a given limit nn.

Algorithm

  1. Create a boolean array of size nn, initially all True
  2. Mark 0 and 1 as not prime
  3. For each number ii from 2 to n\sqrt{n}:
    • If ii is still marked prime, mark all multiples of ii (starting from i2i^2) as not prime
  4. All indices still marked True are prime

Why Start from i²?

When marking multiples of ii, all multiples less than i2i^2 have already been marked by smaller primes (2i2i by 2, 3i3i by 3, etc.).

Time Complexity

O(nloglogn)\Large O(n \log \log n)

Derivation: The inner loop runs np\frac{n}{p} times for each prime pp. Total work:

pnnp=npn1pnloglogn\sum_{p \leq n} \frac{n}{p} = n \sum_{p \leq n} \frac{1}{p} \approx n \log \log n

The sum of reciprocals of primes grows as loglogn\log \log n (Meissel-Mertens constant).

Space Complexity

O(n)O(n)

Boolean array to track primality.

Implementation

def sieve(n: int) -> list[bool]:
    if n < 2:
        return [False] * n

    prime = [True] * n
    prime[0] = prime[1] = False

    for i in range(2, int(n ** 0.5) + 1):
        if prime[i]:
            for j in range(i * i, n, i):
                prime[j] = False

    return prime

Optimizations

Skip even numbers: Only store odd numbers, halving space.

Segmented sieve: Process in blocks for cache efficiency and to handle larger ranges.

Wheel factorization: Skip multiples of small primes (2, 3, 5) during iteration.

On this page