题目链接:204. 计数质数 - 力扣(LeetCode)
会超时的代码:
使用了枚举的方法
方法一:
public static int countPrimes(int n) {
int ans=1;
if (n<=2)
return 0;
for (int i=3;i<n;i++){
boolean flag=true;
for (int j=2;j<i;j++){
if (i%j==0) {
flag=false;
break;
}
}
if (flag)
ans++;
}
return ans;
}
方法二:
public static int countPrimes(int n) {
int ans=0;
for (int i=2;i<n;++i){
boolean flag=true;
for (int j=2;j*j<=i;++j){
if (i%j==0){
flag=false;
break;
}
}
if (flag) {
ans++;
// System.out.print(i+" ");
}
}
// System.out.println();
return ans;
}
不会超时的代码:
使用埃氏筛
如果 xxx 是质数,那么大于 x 的 x 的倍数 2x,3x… 一定不是质数,因此我们可以从这里入手。
我们设 arr[i] 表示数 i 是不是质数,如果是质数则为 1,否则为 0。从小到大遍历每个数,如果这个数为质数,则将其所有的倍数都标记为合数(除了该质数本身),即 000,这样在运行结束的时候我们即能知道质数的个数。
当然这里还可以继续优化,对于一个质数 x,如果按上文说的我们从 2x 开始标记其实是冗余的,应该直接从 x*x 开始标记,因为 2x,3x,…这些数一定在 xxx 之前就被其他数的倍数标记过了,例如 2 的所有倍数,3 的所有倍数等。
public static int countPrimes(int n) {
int[] arr = new int[n];
Arrays.fill(arr, 1);
int ans = 0;
for (int i = 2; i < n; ++i) {
if (arr[i] == 1) {
ans += 1;
if ((long) i * i < n) {
for (int j = i * i; j < n; j += i) {
arr[j] = 0;
}
}
}
}
return ans;
}
测试用例:
System.out.println(countPrimes(10));
运行结果:
4
Process finished with exit code 0