原题链接:204. Count Primes
【优化】
按照题目“Show Hint”提示,如果定义一个函数,判断这个数是否是素数,那么效率会很低:
public int countPrimes(int n) {
if (n <= 2) return 0;
int count = 1;
boolean flag = false;
for (int i = 3; i < n; i += 2)
if (isPrime(i)) count++;
return count;
}
public boolean isPrime(int x) {
int tmp = (int) Math.sqrt(x);
for (int j = 3; j <= tmp; j += 2)
if (x % j == 0) return false;
return true;
}
20 / 20
test cases passed. Runtime: 460 ms Your runtime beats 0.37% of javasubmissions.
【思路】
利用空间换时间,由于所有的合数都可以分解为素数的乘积,定义一个大小为 n 的数组,我们可以利用这个数组记录素数和合数。当我们找到一个素数时,就以这个素数为因子,找出所有以该素数为因子的合数(该合数小于 n):
public int countPrimes(int n) {
if (n <= 2) return 0;
boolean[] notPrime = new boolean[n];
int count = 1;
for (int i = 3; i < n; i += 2) {
if (notPrime[i]) continue;
for (int j = 3; j * i < n; j += 2) //找出所有以i为因子的合数,另一个因子为 j,由于素数不可能为偶数,那么 i 和 j均取做奇数
notPrime[j * i] = true; //将 notPrime[j * i]设置为 true,表示它是一个合数
count++;
}
return count;
}
20 / 20
test cases passed. Runtime: 15 ms Your runtime beats 96.39% of javasubmissions.
【优化】
由于合数可以拆分为素数的乘积。那么,当我们找到一个素数时,就以这个素数为因子,找出所有以该素数为因子的合数(该合数小于 n),相对于上面的思路优化之处在于另一个因子也是素数:
public int countPrimes(int n) {
if (n < 3) return 0;
int primeNum = n / 2; // Count all the odd number
boolean[] isPrime = new boolean[n];
int sqrtN = (int) Math.sqrt(n);
for (int i = 3; i <= sqrtN; i += 2) {
if (!isPrime[i]) {
for (int j = i * i; j < n; j += i * 2) {
primeNum -= (isPrime[j])? 0: 1;
isPrime[j] = true;
}
}
}
return primeNum;
}
20 / 20
test cases passed. Runtime: 9 ms Your runtime beats 100.00% of javasubmissions.