【列出质数】
请列出1~n内的所有质数。
【问题背景】
这是以前在CSDN论坛上看到的一个面试官写给应聘者建议中说到的一个问题,他说自己找到了一种最简单的方法,当然具体是什么方法没写出来。大学的时候学Fortran,经常没事干就琢磨用程序解决实际问题,印象比较深刻的就是9行代码取出1~n内的所有质数,当时自认为是效率最高的代码,列出来和有兴趣的朋友一起讨论,同时欢迎指正。当然更希望能看到那位面试官的答案。
【普通做法】
最常见的做法就是通过求余实现。
int max = 1000000;
boolean[] primes = new boolean[max + 1];
for (int i = 0; i < max + 1; i++)
primes[i] = i % 2 != 0;
primes[1] = false;
primes[2] = true;
for (int i = 5; i < max; i+=2) {
if (!primes[i])
continue;
int sqrt = (int) Math.sqrt(i);
for (int ii = 3; ii <= sqrt; ii++) {
if (i % ii == 0) {
primes[i] = false;
break;
}
}
}
int count = 1;
for (int i = 3; i < max + 1; i+=2){
if (primes[i]) count++;
}
System.out.println(max+"范围内的质数个数为:"+count);
输出结果:78498
计算用时:759 ms
【筛法】
下面通过筛法来实现。
int max = 1000000;
boolean[] primes = new boolean[max + 1];
for (int i = 0; i < max + 1; i++)
primes[i] = i % 2 != 0;
primes[1] = false;
primes[2] = true;
int kk = 3;
int sqrt = (int) Math.sqrt(max);
do {
for (int i = kk * kk; i < max + 1; i += 2 * kk)
primes[i] = false;
do {
kk += 2;
}
while (!primes[kk] && kk <= sqrt);
}while (kk <= sqrt);
int count = 1;
for (int i = 3; i < max + 1; i+=2){
if (primes[i])
count++;
}
System.out.println(max+"范围内的质数个数为:"+count);
输出结果:78498
计算用时:15 ms
【简单分析】
[1]筛法很浪费空间。
[2]对于寻找1~n以内的所有质数,筛法无疑是最快的,因为它几乎不用任何运算就可以将某个质数的所有倍数排除掉。
[3]那位面试官说找到了最简单的方法,我认为只可能是对
for (int i = kk * kk; i < max + 1; i += 2 * kk)
进行改进,考虑过很长时间,不知道该如何改进。