基本思路
其实很简单,不必用深搜广搜,也不必用贪心动规,单是枚举就能搞定!
是的,你没听错!枚举!
从小到大枚举,依次判断是否能整除n,只要有一个数可以整除n,就可以证明n是一个合数,若没有一个数可以整除n,就可以证明n为一个质数。
我们都知道,枚举最重要的就是要确定范围。
因为所有数都能被1整除,n mod n 等于 0,所以范围应该是2~n-1。
但是还要判断n是否为1,因为众所周知,1既不是质数,也不是合数。
代码如下:
bool isPrime(int n) {
if(n == 1) { // 1不是质数
return false;
}
// 枚举范围: 2~n-1
for(int i = 2; i < n; ++i) {
if(n % i == 0) { // 判断n是否能被i整除
return false;
}
}
return true;
}
由于在C++中,return返回后,函数会自动终止执行,所以我们不需要break之类的东西。
优化
枚举范围可以缩小到i * i <= n。
bool isPrime(int n) {
if(n == 1) { // 1不是质数
return false;
}
// 枚举范围: 2~n-1
for(int i = 2; i <= n / i; ++i) { // 为防止越界,故i<=n/i
if(n % i == 0) { // 判断n是否能被i整除
return false;
}
}
return true;
}
再优化
其实还有一种算法叫作埃氏筛,代码如下:
这种算法适合筛批量的素数。
时间复杂度O(nlogn)
void getPrimes(int n) {
memset(prime, 1, sizeof prime); // 排除1的情况
for(int i = 2; i <= n; ++i) {
if(!prime[i]) continue;
for(int j = i << 1; j <= n; j += i) {
prime[j] = 0; // 将素数的倍数筛去
}
}
}
还不够快?
怎么办?
其实我们还可以使用欧拉筛法。
原理和埃氏筛法一样,但是多了一句话:
if(i % prime[j] == 0) break;
这样就可以达到O(n)的效果了!
总结
所以,我们要根据自己需要来选择合适的算法。
不能为了用而用。
不过强烈推荐O(n)的欧拉筛,
速度很快。