We need to count how many prime numbers exist below a given number n. A prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself. So for n = 10, the primes less than 10 are 2, 3, 5, and 7, giving us a count of 4.
Determining whether a single number is prime is straightforward. The difficulty is doing it for every number from 2 to n - 1 when n can be as large as 5 million. Checking each number independently repeats the same divisibility work over and over. The structure of prime numbers allows a faster method that eliminates composites in bulk.
0 <= n <= 5 * 10^6 → Trial division on each number independently takes O(n * sqrt(n)), which is roughly 11 billion operations at the upper bound. The approach has to be closer to O(n log log n).n can be 0 or 1 → The answer is 0 since there are no primes below 2. The solution must handle these without indexing into an empty array.For each number from 2 to n - 1, check whether it is prime by testing divisibility. To determine if a single number k is prime, try dividing it by every integer from 2 up to sqrt(k). If none of them divide k evenly, then k is prime.
Testing up to sqrt(k) suffices: if k = a * b and both a and b were greater than sqrt(k), then a * b > k, a contradiction. So every composite k has at least one factor at or below sqrt(k).
n is less than or equal to 2, return 0 (no primes below 2).count = 0.i from 2 to n - 1:i is prime by testing divisibility from 2 to sqrt(i).count.count.Trial division tests 4, 6, 8, and every other even number against 2 one at a time. The next approach inverts the direction: each prime, once found, eliminates all of its multiples in a single pass.
The Sieve of Eratosthenes reverses the question. Instead of asking "is this number prime?" for each number, we start by assuming every number is prime and then systematically cross out the ones that are not.
If p is a prime, then every multiple of p (2p, 3p, 4p, ...) is composite, so each prime we find lets us mark a whole family of composites in one pass. Sieving with every prime up to sqrt(n) is enough: any composite below n has a prime factor at most sqrt(n), so none survives.
There is one more optimization: when marking multiples of a prime p, we can start from p * p rather than 2 * p, because all smaller multiples of p have already been marked by smaller primes.
Every integer greater than 1 is either prime or a product of primes (the Fundamental Theorem of Arithmetic). Crossing out all multiples of each prime removes every number that has a prime factor smaller than itself, so any number still unmarked at the end has no divisors other than 1 and itself.
Starting at p * p skips nothing: a composite c that is divisible by p but smaller than p * p can be written as c = p * k with k < p. The smallest prime factor q of c is then at most k, which gives q * q <= k * k < k * p = c, so c falls inside the marking range of q and was crossed out when q was processed.
n is less than or equal to 2, return 0.isPrime of size n, initialized to true.isPrime[0] and isPrime[1] to false (0 and 1 are not prime).p starting at 2, while p * p < n:isPrime[p] is true, mark all multiples of p starting from p * p as false.true values in the array.