题目:判断101-200之间有多少个素数,并输出所有素数。
分析:一个素数n就是只有1和n两个因数的数。如果一个数n有除1和n之外的因数,那么这个数就是合数,且这些因数必定在(1,n)中,故只需要把n除以(1,n)中的所有数,如果没有能整除的,n就是素数。
不过(1,n)这个范围比较大,我们可以缩小范围。一个合数n,如果一个数大于n/2,那么这个数必定不是n的因数。因为n除以一个大于n/2的数得到的数必然小于2,不是另一个合数或者素数(合数总是能表达为两个素数或者两个合数或者一个素数和一个合数的乘积)。换句话说,合数n的因数只可能在(1,n/2]中。于是,只要n不能被(1,n/2]中的数整除,n就是素数。
能不能继续缩小范围呢?能。上面说到,合数总是能表达为两个素数或者两个合数或者一个素数和一个合数的乘积。有合数n,n = n的平方根 * n的平方根,如果n的某一个因数比n的平方根大,那么必定还有比n的平方根小的因数。如,n = a * b,a是比n的平方根大的因数,b是n的另一个因数或者另外几个因数的乘积,我们肯定b或得到b的另外几个因数必定比n的平方根小,因为只有这样等式才可能继续成立。换句话说,如果能在(大于n的平方根,n)中找到n的因数,必然也能在(1,小于等于n的平方根)中找到因数。于是,我们把寻找合数n因数的范围缩小到(1,n的平方根]。当n>4时,n的平方根<n/2。
求某个范围素数的Java代码如下:
public List<Integer> getPrimeNumber(int startNum, int endNum) {
// TODO Auto-generated method stub
List<Integer> primeNums = new ArrayList<Integer>();
int i = startNum;
boolean judge = true;
while (i >= startNum && i <= endNum) {
for(int j = 2; j > 1 && j <= Math.sqrt(i); j++){
if(i % j == 0) {
judge = false;
break;
}
}
if(judge == true) {
primeNums.add(new Integer(i));
}
judge = true;
i++;
}
return primeNums;
}
总结:其实,优化求素数算法的过程,就是不断缩小用来判断一个数是否为素数的数集的过程,(1,n的平方根]也并不是最优的数集,可以继续优化,比如(1,n的平方根]的素数组成的集合。到最后,我们还要考虑计算机内存问题,素数是无数的,我们怎么用有限的内存来保存尽可能多的素数,位图数据结构是一种方案。