题:统计所有小于非负整数 n 的质数的数量。
1.枚举法
双重循环进行遍历,第一重遍历n,第二重判断n是否为素数,时间复杂度 o ( n n ) o(n\sqrt{n}) o(nn),空间复杂度为o(1).
int countPrimes(int n) {
int ans = 0;
int flag;
for (int i = 2; i < n; ++i) {
flag = 1;
for(int j = 2; j < int(sqrt(i)) + 1; j++)
{
if(i % j == 0)
{
flag = 0;
break;
}
}
if(flag)
{
ans++;
}
}
return ans;
}
2.埃氏筛
开一个长度为n的bool型数组isprime,第i位表示整数i是否为素数,初始化化为true,从2开始遍历,如果遇到一个数x为素数,计数值加1,则将isprime数组下标为
2
x
,
3
x
,
4
x
…
…
k
x
(
k
x
<
n
<
=
k
x
+
x
)
2x,3x,4x……kx(kx<n<=kx+x)
2x,3x,4x……kx(kx<n<=kx+x)的值置为false。当然其也可以优化,因为
2
x
,
3
x
2x,3x
2x,3x等,会由前面的素数进行更新,只需要从
x
∗
x
,
(
x
+
1
)
∗
x
.
.
.
.
.
x*x,(x+1)*x.....
x∗x,(x+1)∗x.....开始更新及可。
时间复杂度:
o
(
n
l
o
g
l
o
g
(
n
)
)
o(nloglog(n))
o(nloglog(n))(具体怎么计算我也不太了解),空间复杂度
o
(
n
)
o(n)
o(n).
class Solution {
public:
int countPrimes(int n) {
vector<int> isPrime(n, 1);
int ans = 0;
for (int i = 2; i < n; ++i) {
if (isPrime[i]) {
ans += 1;
if ((long long)i * i < n) {
for (int j = i * i; j < n; j += i) {
isPrime[j] = 0;
}
}
}
}
return ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
3.线性筛
埃氏筛也存在重复计算的情况,对于6, x = 2 x=2 x=2和 x = 3 x=3 x=3时均对其进行了一次运算,导致了时间的浪费。我们考虑对于每一个合数只进行计算一次,使时间复杂度降到线性。对于任意一个合数x,我们能写成 x = p y x=py x=py的形式,其中p为x的最小素因子,我们只在遍历到y时,通过素数p对其进行一次操作。仍然从2开始到n进行遍历,如果isprime是true,将其加入prime容器,然后将对于当前所遍历到的i,在其中,我们用j遍历prime容器,将 i ∗ p r i m e [ j ] i*prime[j] i∗prime[j]置为false,当遇到i可以被 p r i m e [ k ] prime[k] prime[k]整除,即 i = p r i m e [ k ] ∗ t i=prime[k] * t i=prime[k]∗t的形式时退出,因为对于prime之后的素数来说 i ∗ p r i m e [ j ] ( j > k ) i*prime[j](j>k) i∗prime[j](j>k)不应由 p r i m e [ j ] prime[j] prime[j]更新,而在遍历到 p r i m e [ j ] ∗ t prime[j]*t prime[j]∗t时由 p r i m e [ k ] prime[k] prime[k]更新(因为 i ∗ p r i m e [ j ] = p r i m e [ k ] ∗ t ∗ p r i m e [ j ] i*prime[j]=prime[k] * t*prime[j] i∗prime[j]=prime[k]∗t∗prime[j],而 p r i m e [ k ] < p r i m e [ j ] prime[k]<prime[j] prime[k]<prime[j],由最小的素数更新)。
int countPrimes(int n) {
vector<int>prime;
bool *flag = new bool[n];//flag即为isprime
memset(flag,1,n*sizeof(bool));//初始化
for(int i = 2; i < n; i++)
{
if(flag[i])
{
prime.push_back(i);
}
for(int j = 0; j < prime.size() && i * prime[j] < n; j++)
{
flag[prime[j]*i] = false;
if(i % prime[j] ==0)
{
break;
}
}
}
return prime.size();
}