统计[2,n)区间内的素数个数。
1.枚举
[2,n) 从2开始遍历,一个一个数去判断是否是素数。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int prime[N]; //prime数组存放素数
int isPrime(int n) //判断n是否为素数,是素数返回1,不是返回0
{
for(int i=2;i*i<=n;i++){
if(n % i == 0) return 0;
}
return 1;
}
int main()
{
int n;
cin>>n;
int res = 0;
for(int i=2;i<n;i++){
if(isPrime(i)) prime[res++] = i;
}
//输出素数
cout<<res<<'\n';
for(int i=0;i<res;i++) cout<<prime[i]<<" ";
return 0;
}
时间复杂度:O(n√n)
2.埃氏筛
[2,n) 从2开始遍历,2为素数,记下,并将2的所有倍数划去;接下来3为素数,记下,并将3的所有倍数划去;4是2的倍数,已经被划去,所以接下来是5,5是素数记下,并将5的所有倍数划去;以此类推直到n。
有个动图可以很直观地理解这个筛法。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int prime[N]; //prime数组记录状态,1为素数,0不是素数
int res = 0; //res记录素数个数
int main()
{
int n;
cin>>n;
memset(prime,1,sizeof(prime)); //初始化prime数组全部为1
for(int i=2;i<n;i++){
if(prime[i]){
res++;
for(int j=2*i;j<n;j+=i) prime[j] = 0; //i的所有倍数都不是素数,状态更新为0
}
}
//输出素数
cout<<res<<'\n';
for(int i=2;i<n;i++){
if(prime[i]) cout<<i<<" ";
}
return 0;
}
时间复杂度:O(n㏒n㏒n)
3.线性筛
在埃氏筛的遍历过程中,会出现重复标记的情况。例如30既是2的倍数也是3的倍速还是5的倍数,那么在遍历2的所有倍数时会被标记一次,在遍历3的倍数时又会被标记一次,在遍历5的倍数时又会被标记一次。可以优化埃氏筛,但还是会有被重复标记的数,而线性筛可以实现完全无重复的解法。
每一个合数都可以以唯一形式被写成质数的乘积。也就是说,一个合数可以表示成一个质数和一个数的乘积。
所以if(i % prime[j] == 0) break;
举个栗子,i=8,i % 2 == 0,所以对于i=8就只需要检查prime[1]=2即可,因为对于大于prime[1]的质数,例如3,有:8 * 3 = 2 * 4 * 3 = 12 * 2,也就是说24(8 * 3 = 24)并不需要在8时检查,在12时才检查。
参考https://blog.csdn.net/leolin_/article/details/6642126
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int prime[N]; //prime数组存放素数
int res = 0; //res记录素数个数
int vis[N]; //0为素数,1不是素数
int main()
{
int n;
cin>>n;
for(int i=2;i<n;i++){
if(!vis[i]) prime[res++] = i; //素数存入数组
for(int j=0;j<res&&i*prime[j]<n;j++){
vis[i*prime[j]] = 1;
if(i % prime[j] == 0) break; //遇到i最小的素数因子
}
}
cout<<res<<'\n';
for(int i=0;i<res;i++){
cout<<prime[i]<<" ";
}
// for(int i=2;i<n;i++){
// if(!vis[i]) cout<<i<<" ";
// }
return 0;
}
时间复杂度:O(n)
4.奇数筛
已知偶数不一定是质数,而质数一定是奇数,所以只需要在奇数范围内标记出合数,剩下的奇数便都是质数了。
另外,奇数 * 奇数 = 奇数,奇数 * 偶数 = 偶数。
根据上述条件,可以在已经有的埃氏筛的基础上进行优化。可以在遍历时选择i+=2避开偶数,也可以直接将状态数组中偶数全部改为0。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int prime[N]; //prime数组记录状态,1为素数,0不是素数
int res = 0; //res记录素数个数
int main()
{
int n;
cin>>n;
// memset(prime,0,sizeof(prime));
prime[2] = 1;
for(int i=3;i<n;i++){
if(i%2 == 1) prime[i] = 1; //奇数标记为1
else prime[i] = 0; //偶数标记为0
}
for(int i=2;i<n;i++){
if(prime[i]){
res++;
for(int j=2*i;j<=n;j+=i) prime[j] = 0;
}
}
//输出素数
cout<<res<<'\n';
for(int i=2;i<n;i++){
if(prime[i]) cout<<i<<" ";
}
return 0;
}