Count Primes
Given an integer n, return the number of prime numbers that are strictly less than n.
Algorithm
Sieve of Eratosthenes is an efficient algorithm to find all prime numbers up to a given limit. The algorithm works by iteratively marking the multiples of each prime number starting from 2. The time complexity is O(n log log n) and the space complexity is O(n). The algorithm works as follows:
- Create a boolean array
is_primeof sizeninitialized totrue. - Set
is_prime[0]andis_prime[1]tofalsesince 0 and 1 are not prime. - For each number
ifrom 2 to the square root ofn, ifis_prime[i]istrue, mark all multiples ofiasfalse. - Count the number of
truevalues in theis_primearray, which gives the count of prime numbers less thann.
Solution
#include <cmath>
#include <vector>
using namespace std;
class Solution {
public:
int countPrimes(int n) {
if (n <= 1) // There are no primes less than 2
return 0;
vector<bool> isPrime;
// initialize the isPrime vector with true values
for (int i = 0; i < n; i++) {
isPrime.push_back(true);
}
// 0 and 1 are not prime numbers
isPrime[0] = false;
isPrime[1] = false;
// Sieve of Eratosthenes
for (int p = 2; p < sqrt(n); p++) {
if (isPrime[p])
for (int i = p * p; i < n; i += p)
isPrime[i] = false;
}
// Count the number of primes
int primes = 0;
for (int i = 0; i < n; i++) {
if (isPrime[i]) {
primes++;
}
}
return primes;
}
};Optimisation
The first optimization is to initialize isPrime in a different way, using a
vector constructor that takes the size and initial value. This avoids the need
for a loop to fill the vector with true values.
vector<bool> isPrime(n, true);The second optimization is to set the upper limit of the outer loop to p*p < n instead of p<sqrt(n). This is because sqrt() is inefficient for
large numbers and p*p is faster.
for (int p = 2; p * p < n; p++) {
if (isPrime[p]) {
for (int i = p * p; i < n; i += p) {
isPrime[i] = false;
}
}
}The third optimisation is to run the Sieve only for odd numbers in a array of
size n/2 and then just add 1 to the final count to account for the number
2.
vector<bool> isPrime((n + 1) / 2, true);
isPrime[0] = false; // 1 is not prime
for (int p = 3; p * p < n; p += 2)
{
if (isPrime[p / 2]) {
for (int i = p * p; i < n; i += 2 * p) {
isPrime[i / 2] = false;
}
}
}
int primes = 1; // Count 2 as prime
for (int i = 1; i < isPrime.size(); i++) {
if (isPrime[i]) {
primes++;
}
}
return primes;