朴素做法
利用枚举的思想
从2开始一直到n,每次循环都把当前枚举的这个数到n之间所有的倍数全部删掉,那么最后剩下的就是质数了
const int N=1000100;// 数据范围
bool st[N];//用来记录每个数是否被删除
int prime[N];//用来记住所有的质数
int cnt;//用来统计个数
// 最小的一个素数是 2
for(int i = 2;i <= n;i++){
if(!st[i]){//如果说这个数没有被删除掉的话,那么这个数就是质数
prime[cnt++]=i;//这里用来记住用到了prime数组中的哪一个下标,如果只是数量的话,那么最后输出cnt就好了
}
//开始枚举,i的所有倍数,如果找到了就把这个点标记成true
for(int j = i+i;j <= n;j=j+i){
st[j]=true;
}
}
//最后只要枚举prime数组就能得到[1,n]中所有的素数
埃式优化
不用每个点都进行枚举,如果说这个点之前已经被删除了,那意味着这个点已经不是质数了,我们就不需要进行枚举这个数的倍数,从而可以,减少循环的次数,进而降低时间复杂度
const int N=1000100;// 数据范围
bool st[N];//标记每个点是不是已经被删除了
int prime[N];
int cnt;
for(int i = 2;i <= n;i++){
if(!st[i]){ //如果说,当前这个点没有被删除,说明他就是一个质数
prime[cnt++] = i;//用来记录所有的素数
for(int j = i+i;j <= n;j=j+i){
st[j] = true;
}
}
}
线性优化
x会被其最小的质因子筛去
const int N=1000100;
bool st[N];
int cnt;
int primes[N]; // primes[]存储所有素数
for (int i = 2; i <= n; i ++ ){
if (!st[i]){
primes[cnt ++ ] = i;
}
for (int j = 0; primes[j] <= n / i; j ++ ) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
204.计数质数
朴素做法
class Solution {
public int countPrimes(int n) {
int res = 0 ;
boolean[] st = new boolean[n+1];
for(int i = 2 ;i < n;i++){
if(!st[i]) res++;
for(int j = i ;j<n;j+=i){
st[j] = true;
}
}
return res;
}
}
埃式筛法
class Solution {
public int countPrimes(int n) {
int res = 0 ;
boolean[] st = new boolean[n+1];
for(int i = 2 ;i < n;i++){
if(!st[i]){
res++;
for(int j = i ;j<n;j+=i){
st[j] = true;
}
}
}
return res;
}
}
线性筛法
class Solution {
// 线性筛法
public int countPrimes(int n) {
List<Integer> primes = new ArrayList<>();
boolean[]st = new boolean[n+1];
for(int i = 2;i < n;i++){
if(!st[i]) primes.add(i);
for(int j = 0;i * primes.get(j)< n;j++){
st[i*primes.get(j)] = true;
if(i%primes.get(j) == 0) break;
}
}
return primes.size();
}
}