基本数论-素数判断
一、暴力求解
1、一个共识
x = a*b且x = sqrt(x)*sqrt(x) => a==b==sqrt(x)或者a<sqrt(x) 且 b > sqrt(x),即要么a==b要么一个大于根号x一个小于根号x
且a = x/b,那么我们只用判断小于sqrt(x)的数是否可以整除x即可。
2、暴力求法(O(n^(2/3)))
bool isPrime(int x){
for(int i=2;i<=sqrt(x);i++){
if(x%i==0) return false;
}
return true;
}
void getPrime(int x){
for(int i=1;i<=x;i++){
if(isPrime(i)) cout<<i;
}
}
3、素数普通筛选(n*log(n))
思想:任何一个素x = 素数*一个数,那么我们可以在找到一个素数的时候,再花n/i的时间去把现在可以确定不是素数的数给标记出来。
如:已知2是一个素数那么:2,4,6,8,10,12...2*i都不是素数。
那么时间复杂度为:n/2+n/3+n/5+......+n/p,p为小于n的素数那么渐进时间复杂度为O(n*log(n))
void getPrime(int x,int* primes){ for(int i=2;i<=x;i++){ if(primes[i]==0){ for(int j=2;j*i<=x;j++) primes[j*i] = 1; } } }
4、素数筛选之线性筛选(o(n))
由3我们可以知道,任何一个数字都可以有一个素数乘一个数得到。比如2是素数那么4,6,8,10,12,14,16....2*i都不是素数了,比如3是素数那么6,9,12,15...3*i都不是素数了,我们
可以看出在我们标记不是素数的时候6,12等在2中标记过,在3中也被标记过这样一来就多了很多重复的操作,那么怎么去优化呢?
我们最容易想到的就是在int j这个循环中加入,prime[j*i]!=1这个标志,就可以很容易的跳过多余的标记,那么我们总共标记了n个元素所以时间复杂度为O(N).
void getPrimeLine(int x,int* primes){ for(int i=2;i<=x;i++){ if(primes[i]==0){ for(int j=2;j*i<=x&&primes[j*i]!=1;j++) primes[j*i] = 1; } } }
或者我们可以根据当前的已知的素数来标记如已知 1,2,3,5现在第6次标记就用1,2,3,5分别乘2,3,4,5,6这样每次乘出来的也不一样最终也不会重复标记,因而时间复杂度为O(N)
原文地址:https://www.cnblogs.com/jake9402/p/10199567.html