题意
计算小于n的整数中素数的个数。
思路
算法1
埃氏筛(Eratosthenes),时间复杂度 O(nloglogn) 。
从2开始,每个素数的整数倍都是合数。
优化:若i是素数,从 i∗i 开始筛除合数而不是 i∗2
代码:
class Solution {
public:
int countPrimes(int n) {
vector<int> notPrime(n, 0);
for (int i = 2; i < n; i++) {
if (!notPrime[i]) {
for (long long j = (long long) i * i; j < (long long) n; j += i) {
notPrime[j] = 1;
}
}
}
//1 is not prime
int cnt = 0;
for (int i = 2; i < n; i++) {
if (!notPrime[i]) cnt++;
}
return cnt;
}
};
算法2
快速线性筛法,时间复杂度 O(n)
确保:
- 每个合数都会被筛除掉。
- 每个合数只会被筛除一遍。
优于埃氏筛的思想:12可以由6 * 2筛除掉,也可以由3 * 4筛除掉,会重复筛选,因为我们需要一定的措施来确保每个合数只会被筛除一遍。
结合代码分析:
class Solution {
public:
int countPrimes(int n) {
vector<int> prime(n, 0);
vector<int> notPrime(n, 0);
int tot = 0;
for (int i = 2; i < n; i++) {
#1 if (!notPrime[i]) prime[tot++] = i;
#2 for (int j = 0; j < tot, (long long) prime[j] * i < (long long) n; j++) {
notPrime[i * prime[j]] = 1;
#3 if (i % prime[j] == 0) break;
}
}
return tot;
}
};
#1 若i没有被筛除,那么我们将i添加到素数表内。
#2 通过
i⋅prime[j]
来筛除合数:
1. 当
i
是素数的时候,有
2. 当
i
是合数的时候,从1我们我们知道