1 求解n以内的素数个数
1.1 暴力法
略
1.2 埃式筛法
我们考虑这样一个事实:如果 x 是质数,那么大于 x 的 x 的倍数 2x,3x… 一定不是质数,因此我们可以从这里入手。
我们设 isPrime[i] 表示数 i 是不是质数,如果是质数则为 1,否则为 0。从小到大遍历每个数,如果这个数为质数,则将其所有的倍数都标记为合数(除了该质数本身),即 0,这样在运行结束的时候我们即能知道质数的个数。
这种方法的正确性是比较显然的:这种方法显然不会将质数标记成合数;另一方面,当从小到大遍历到数 xx 时,倘若它是合数,则它一定是某个小于 x 的质数 y 的整数倍,故根据此方法的步骤,我们在遍历到 y 时,就一定会在此时将 x 标记为 isPrime[x]=0。因此,这种方法也不会将合数标记为质数。
当然这里还可以继续优化,对于一个质数 x,如果按上文说的我们从 2x 开始标记其实是冗余的,应该直接从 x⋅x 开始标记,因为 2x,3x… 这些数一定在 x 之前就被其他数的倍数标记过了,例如 2 的所有倍数,3 的所有倍数,…,x-1的所有倍数。
两个要注意的点:
- 当前要判断的数
x
为质数,才需要赋值它的倍数2x
,3x
,4x
为合数 - 关于倍数,当要将
x
的倍数置为合数时,其实可以直接从x*x倍开始,因为2 ~ x-1
倍,早已被2 ~ x-1
的倍数计算过了。
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-by-leetcode-solution/
int countPrimes(int n) {
bool prime[5000000 + 7];
memset(prime, true, sizeof(prime));
prime[0] = false;
prime[1] = false;
int ans = 0;
for (int i=2; i<n; ++i) {
if (prime[i] == true) {
++ ans;
if ((long long)i*i < n) {
for (int j=i*i; j<n; j+=i) {
prime[j] = false;
}
}
}
}
return ans;
}
1.3 线性筛法
2 欧拉公式
欧拉公式,用来解决所有小于n中的正整数中有多少个与n互质。