GeeksforGeeks Medium

Sieve of Eratosthenes

Given n, return every prime number less than or equal to n.

mathsprimessievearray
Open on GeeksforGeeks ↗
02

Intuition

💡

Testing each number for primality separately costs O(sqrt n) per number, so printing all primes up to n is O(n sqrt n) — far too slow at n = 10^6. The cost is in re-deriving, for each candidate, facts we already know. Turn it around: instead of asking each number whether it is prime, let each prime announce its own multiples as composite. Start with everything marked prime, walk upward, and whenever you meet a number that is still marked, it is prime — so cross out all of its multiples. What is left standing at the end is exactly the primes.

03

Approach

1

Name the brute force and its cost

The straightforward answer loops i from 2 to n and calls an isPrime(i) helper that trial-divides up to sqrt(i). That is O(n sqrt n) overall. At n = 10^5 it is already sluggish; at 10^6 it is hopeless. The bottleneck is the primality check, so the goal is to make that check O(1).

2

Precompute a lookup table instead of testing

Allocate a boolean array of size n + 1 and initialise every entry to 'prime'. Immediately clear indices 0 and 1, since neither is prime by definition. Now the check prime[i] is a single array read — O(1). The entire question becomes how to fill this array cheaply.

3

Let each prime cross out its own multiples

Walk i upward from 2. Take n = 30. prime[2] is still set, so 2 is prime — and every multiple of 2 (4, 6, 8, ... 30) has 2 as a factor, so it cannot be prime. Clear them all. Move to 3: still set, so prime; clear 6, 9, 12, ... 30. Move to 4: it is already cleared, which tells us 2 divides it — and every multiple of 4 is also a multiple of 2 and has therefore already been cleared. So a cleared number needs no work at all. Skip it. That skip is what keeps the algorithm fast.

4

Two bounds that cut the work further

First, the inner loop can start at i i rather than 2 i. Any smaller multiple i k with k < i has a factor smaller than i and was cleared during that smaller factor's pass. Second, the outer loop only needs to run while i i <= n: past that point every remaining composite would need a factor above sqrt(n) paired with one below it, and the one below already struck it. Together these bring the total to O(n log log n).

04

Solution & live demo

python
1class Solution:
2 def sieve(self, n):
3 prime = [1] * (n + 1)
4 if n >= 0: prime[0] = 0
5 if n >= 1: prime[1] = 0
6 i = 2
7 while i * i <= n:
8 if prime[i]:
9 for j in range(i * i, n + 1, i):
10 prime[j] = 0
11 i += 1
12 return [k for k in range(2, n + 1) if prime[k]]
05

Edge cases

n < 2

There are no primes; the array is entirely cleared by the explicit prime[0] = prime[1] = 0 step and the loops never execute, so an empty list is returned.

n == 2

The outer loop condition i * i <= n fails immediately at i = 2, nothing is crossed out, and 2 is correctly reported as prime.

Multiple queries over the same range

Build the sieve once and reuse it. This is the real reason to prefer it over repeated isPrime calls — after the O(n log log n) setup, every subsequent primality question costs O(1).

06

Complexity

Time
O(n log log n)
Space
O(n)
The array is the price of O(1) primality checks afterwards. Calling an O(sqrt n) isPrime for every number instead is O(n sqrt n).