题目:
输出小于n的质数的个数
方法一:
能不能快速判断一个数字n是不是质数呢?
1、遍历所有小于n的整数,如果都不可以整除那么n为质数
2、遍历所有小于sqrt(n)的整数,如果都不可以整除那么n为质数
3、遍历所有小于sqrt(n)的质数,如果都不可以整除那么n为质数
显然3是最快的做法,因此我们在搜索到一个质数后要将其保存到数组后面,下次直接遍历质数数组来判断n是不是质数
class Solution {
public:
int countPrimes(int n) {
if (n < 3)
{
return 0;
}
vector<int> primes;
primes.push_back(2);
int count = 1;
for (int i = 3; i < n; ++i)
{
bool flag = false;
for (auto p : primes)
{
if (i % p == 0)
{
flag = true;
break;
}
if (p * p > i)
{
break;
}
}
if (!flag)
{
++count;
primes.push_back(i);
}
}
return count;
}
};
方法二:
能不能反过来思考,我找出小于n的所有合数,然后剩下的就是质数。任何一个合数都存在质素因数,所以进行按如下规则查找合数。
1、标注所有小于n的2的倍数(不包括2),剩下的最小的大于2的未被标记的数是3,质数。
2、标注所有小于n的3的倍数(不包括3),剩下的最小的大于3的未被标记的数是5,质数。
3、……
另外,对于质数 p,排除掉p的整数倍后,剩下的元素中满足 p<k<p∗p的元素k均为质数,也就是说在p和p*p之间的合数都在之前的迭代中被标注了。这是显然的,因为如果k没有被标记,说明k的所有质因子都大于p,这与k<p*p矛盾,所以我们只需要标注完小于sqrt(n)的质数的整数倍后就可以得到所有的质数的数量了。
class Solution {
public:
int countPrimes(int n) {
if (n <= 2) return 0;
bool *p = new bool[n];
memset(p, true, sizeof(bool) * n);
for (int i = 2; i * i < n; i++)
{
if (p[i])
{
for (int j = 2; j * i < n; j++)
p[i * j] = false;
}
}
int cnt = 0;
for (int i = 2; i != n; i++)
if (p[i]) cnt++;
delete[] p;
return cnt;
}
};