一.解法
https://leetcode-cn.com/problems/count-primes/
要点:埃拉托色尼筛选法
Python,C++,Java都用了相同的埃拉托色尼筛选法。
一开始采用写一个isPrime函数判断一个数是不是素数,然后遍历2到n-1计算个数的方法,结果超时。
于是学习了埃拉托色尼筛选法来计算质数,这个方法类似一种排除法,因为一个合数总是可以分解成若干个质数的乘积,所以如果把质数(最初只知道2是质数)的倍数都去掉,那么剩下的就是质数了。
首先从 2 开始,我们知道 2 是一个素数,那么 2 × 2 = 4, 3 × 2 = 6, 4 × 2 = 8... 都不可能是素数了。
然后我们发现 3 也是素数,那么 3 × 2 = 6, 3 × 3 = 9, 3 × 4 = 12... 也都不可能是素数了。
以此类推得到答案,注意代码中有两个优化的点,第一个点是由于因子的对称性,,外层的 for 循环只需要遍历 [2,sqrt(n)] 就够了,第二个点是内层的for循环可以写成for (int j = i * i; j < n; j += i),因为比如 n = 25,i = 4 时算法会标记 4 × 2 = 8,4 × 3 = 12 等等数字,但是这两个数字已经被 i = 2 和 i = 3 的 2 × 4 和 3 × 4 标记了,会有重复标记的地方。
二.Python实现
class Solution:
def countPrimes(self, n: int) -> int:
ans = [True] * n
count = 0
for i in range(2, int(n**0.5)+1):
if ans[i]:
for j in range(i*i, n, i):
ans[j] = False
for k in range(2, n):
if ans[k]:
count+=1
return count
三.C++实现
class Solution {
public:
int countPrimes(int n) {
if(n==0||n==1||n==2) return 0;
vector<bool> ans;
int count=0;
for(int i=0;i<n;i++){
ans.push_back(true);
}
for(int i=2;i*i<n;i++){
if(ans[i]){
for(int j=i*i;j<n;j=j+i){
ans[j]=false;
}
}
}
for(int i=2;i<n;i++){
if(ans[i]) count++;
}
return count;
}
};
四.java实现
class Solution {
public int countPrimes(int n) {
boolean[] isPrim = new boolean[n];
Arrays.fill(isPrim, true);
for (int i = 2; i * i < n; i++)
if (isPrim[i])
for (int j = i * i; j < n; j += i)
isPrim[j] = false;
int count = 0;
for (int i = 2; i < n; i++)
if (isPrim[i]) count++;
return count;
}
}