1. 题目描述
统计所有小于非负整数 n 的质数的数量。
2. 思路
(1)暴力解法(超出时间限制)
从2开始遍历,对每个数字检测是否为质数,直到n。
检测方法:如果从2开始到它本身(不包括本身)的范围,有一个数能被它整除,则说明这个数不是质数。
(2)优化的暴力解法(超出时间限制)
1)所有的偶数都不是质数,除了0,2,所以可以先筛选掉。
2)对正整数 n ,如果用2到 √n 之间(注意要包含边界)的所有整数去除,均无法整除,则n为质数。
对条件(2)进行处理时,对于除数,可以跳过所有的偶数部分,即从3开始检测,每次+2。
(3)厄拉多塞筛法
在进行顺序遍历时,每取得一个数(排除0、1),遍历它之后所有小于n的数,将它所有的倍数(排除0、1、本身)都清除,那么,剩下的数则为质数。比如取得2,则排除小于n的所有倍数。
3. 代码
(1)暴力解法
public int countPrimes1(int n) {
if(n < 2)
return 0;
int res = 0;
for(int i = 2; i < n; i++){
boolean flag = true;
for(int j = 2; j < i; j++){
if(i % j == 0){
flag = false;
break;
}
}
if(flag)
res++;
}
return res;
}
(2)优化的暴力解法
public int countPrimes2(int n) {
if(n <= 2)
return 0;
int res = 1;//2为质数
for(int i = 3; i < n; i++){
boolean flag = true;
//如果可以整除2,则不是偶数,所以可以先筛选掉所有偶数
if((i & 1) == 0){
continue;
}
//对正整数 n ,如果用 2 到 √n 之间(注意要包含边界)的所有整数去除,均无法整除,则 n 为质数。
for(int j = 3; j * j <= i; j = j+2){//由于前面已经筛掉所有负数,所以j可以+2跳过偶数部分
if(i % j == 0) {
flag = false;
break;
}
}
if(flag)
res++;
}
return res;
}
(3)厄拉多塞筛法
public int countPrimes3(int n) {
if(n <= 2)
return 0;
boolean[] flag = new boolean[n];//不包括n
//初始化设置所有的数为质数
Arrays.fill(flag, true);
int res = 0;
for(int i = 2; i < n; i++){
if(flag[i])
res++;
//i的所有倍数均不为质数
for(int j = i + i; j < n; j = j+i){
flag[j] = false;
}
}
return res;
}