博主在刷Leetcode 上的题目,看到一道题目,觉得很有意思。做出来之后,就想到分享一下。
题目是:
Count the number of prime numbers less than a non-negative number n.
意思就是输入一个大于数字0的数字,然后输出这其中有多少个质数。
Example:
Input: 10
Output: 4
Explanation: There are 4 prime numbers less than 10, they are 2, 3, 5, 7.
如果还未学到算法的同学,应该会想到用两次循环来实现。但是这种方法需要时间复杂度得O(n^2), 这样就跑起来很慢的。对于这种题目肯定这种方法不适合的,所以得另想其他方法。
就想到之前上课的时候学到“埃拉托色尼筛选法",这份方法的英文名叫做Sieve of Eratosthenes。
这种算法是古希腊数学家埃拉托色尼提出的一种筛选法,是针对自然数列中的自然数而实施的,用于求一定范围内的质数。
这个算法的步骤是:
- 先把1删除
- 读取队列中当前最小的数2,然后把2的倍数删去
- 读取队列中当前最小的数3,然后把3的倍数删去
- 读取队列中当前最小的数5,然后把5的倍数删去
- 读取队列中当前最小的数7,然后把7的倍数删去
- 如上所述直到需求的范围内所有的数均删除或读取
现在就上代码,是用Java来写的:
class Solution{
public int countPrimes(int n){
// 声明把输入进来的范围的数字全部放到数组中
boolean[] primes = new boolean[n];
// 将所有的数字全都声明为true
for(int i = 2; i<primes.length; i++){
primes[i] = true;
}
// 这是将质数的倍数全部赋值为False
for(int i = 2; i*i<primes.length; i++){
if(primes[i]){
for(int j = i; j*i < primes.length; j++){
primes[j*i] = false;
}
}
}
// 下面就开始数数组中哪一个数字是true, 为true的说明这个数字是质数
int count = 0;
for(int i = 2; i<primes.length; i++){
if(primes[i]) count++;
}
return count;
}
}
上面是用Java来写的,同一个原理也用C来写一下吧。
int countPrimes(int n){
// 声明动态数组,跟在Java中的类似
bool *isPrime;
isPrime = (bool*)malloc(sizeof(bool)*n);
for(int i = 2; i<n; i++){
isPrime[i] = true;
}
for(int i = 2; i*i<n; i++){
if(isPrime[i]){
for(int j = i; i*j < n; j++){
isPrime[j*i] = false;
}
}
}
int count = 0;
for(int i = 2; i<n; i++){
if(isPrime[i]) count++;
}
// 释放内存,不然会用内存泄漏的危险
free(isPrime);
return count;
}
上面的代码就可以实现这道题目了。虽然做出来了,但是不敢说这个方法是最优的。有什么做的不对的,请指出来。