素数的定义:素数是一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数。在自然数中2是最小的质数。
给定一个整数n,判断其是否为素数
首先我们可以设置一个布尔类型的函数,设置一个整数n,因为素数的约数不可能超过n,所以只要检查一下2~n-1的所有整数能否整除n,就可以判断n是不是素数。若b是n的一个约数,则有n/b也是n的约数,由n=b*(n/b),可知min(b,n/b)<=n。因此只需要检查2~n的范围就可以得出n是否为素数。
bool is_prime(int n){
for(int i=2; i*i<=n; i++){
if(n%i==0) return false;//可被整除,不是素数
}
return n!=1;//去除1时的情况
}
亦或是利用约数枚举
vector<int> is_prime(int n){
vector<int> res;
for(int i=2; i*i<=n; i++){
if(n%i==0){
res.push_back(i);
if(i!=n/i) res.push_back(n/i);
}
}
return res;//返回res,利用是否为空进行判断
}
int main(){
cin>>n;
vector<int> res;
res = is_prime(n);
if(!res.empty()||n==1){//去除为1的情况
cout<<"no"<<endl;
}else{
cout<<"yes"<<endl;
}
return 0;
}
由上述算法可知,若是只对单一整数进行素数判断,那么复杂度为O(n)的算法就够了,但我们常常会遇到另一种情况——给出一个自然数n,问n以内素数的个数。
素数的个数
求解n以内的素数的个数(包括n本身),在2~n的范围内,先从最小的整数2开始搜索,可知在2~n的范围内无可整除其的其他数,因此2为素数,所以可以删除2~n范围内所有2的倍数。执行完上述操作后,从当前最小值3开始搜索,可知在范围内无可整除其的其他数,因此3为素数,所以可以删除2~n范围内所有3的倍数,以此类推执行后续操作……该方法被称为埃氏筛法。
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
2 | 3 | - | 5 | - | 7 | - | 9 | - | 11 | - | 13 | - | 15 | - | 17 | - | 19 | - |
2 | 3 | - | 5 | - | 7 | - | - | - | 11 | - | 13 | - | - | - | 17 | - | 19 | - |
埃氏筛法
is_prime[MAX_N];
int sieve(int n){
int ans = 0;//用于记录素数的个数
for(int i=0; i<=n; i++){
is_prime[i] = true;//初始化所有值为true
}
is_prime[0] = is_prime[1] = false;//将0与1除外
for(int i=0; i<=n; i++){
if(is_prime[i]){
ans++;
//将j初始化为i的2倍,在2~n的范围内,j不断加i,以i的倍数的身份逐渐递增至n
for(int j=2*i; j<=n; j+=i){
is_prime[j] = false;
}
}
}
return ans;
}
若是想要记录n以内素数值是那些,可以利用数组进行存储记录,依次枚举n以内的素数
prime[ans++] = i;
区间内的素数的个数
给定两个自然数a与b,问区间[a,b)内有多少素数。由上述的条件可知,b以内的最小合数的值一定不超过n,所以可以将埃氏筛法运用在区间求解中(当然也可以利用最开始的约数枚举方法来进行求解,但复杂度相对较高),可以设置两个布尔类型的数组,prime_small与is_prime,两个数组分别用来管理[2,b)与[a,b),从[2,b)筛得素数后,在[a,b)中将其倍数删除,从而得到[a,b)中的素数。
typedef long long ll;
bool prime_small[MAX_N];
bool is_prime[MAX_N];
void sieve(ll a,ll b){
for(int i=0; (ll)i*i<b; i++){
prime_small[i] = true;
}
for(int i=0; i<b-a; i++){
is_prime[i] = true;
}
for(int i=0; (ll)i*i<b; i++){
if(prime_small[i]){
for(int j=2*i; j<b; j++){//筛[2,√b)
prime_small[j] = false;
}
for(ll j=max(2LL,(a+i-1)/i)*i; j<b; j+=i){//筛[a,b)
is_prime[j-a] = false;
}
}
}
}