前言:距离上次写博客,已经将近过去十天了,很遗憾没有连续持更博客,因为刚开学手忙脚乱的学习任务,今天终于有空可以静下心来,好好总结一下前天所学的新的算法——埃筛法
统计N以内的素数
素数:只能被1和自身整除的数,0、1除外
解法一:暴力算法
直接一个个统计是否可以被除一以外以及自己整除,直接从2开始遍历
public int countPrimes(int n) {
int ans = 0;
for (int i = 2; i < n; ++i) {
ans += isPrime(i) ? 1 : 0;
}
return ans;
}//i如果能被x整除,则x/i肯定能被x整除,因此只需判断i和根号x之中较小的即可
public boolean isPrime(int x) {
for (int i = 2; i * i <= x; ++i) {
if (x % i == 0) {
return false;
}
}
return true;
}
解法二:埃筛法
利用合数的概念
(
非素数
)
,素数
*n
必然是合数,因此可以从
2
开始遍历,将所有的合数做上标记
public static int eratosthenes(int n) {
boolean[] isPrime = new boolean[n];
int ans = 0;
for (int i = 2; i < n; i++) {
if (!isPrime[i]) {
ans += 1;
for (int j = i * i; j < n; j += i) {
isPrime[j] = true;
}
}
}return ans;
}
注意:j+=i:相当于逐渐递增系数2
将合数标记为
true
,
j = i * i
从
2 * i
优化而来,系数
2
会随着遍历递增(
j += i
,相当于递增了系数
2
),
每一个合数都会有两个比本身要小的因子
(0,1
除外
)
,
2 * i
必然会遍历到这两个因子
当
2
递增到大于根号
n
时,其实后面的已经无需再判断(或者只需判断后面一段),而
2
到根号
n
、实际
上在
i
递增的过程中已经计算过了,
i
实际上就相当于根号
n
例如:
n = 25
会计算以下
2 * 4 = 8
3 * 4 = 12
但实际上
8
和
12
已经标记过,在
n = 17
时已经计算了
3 * 4
,
2 * 4