LeetCode 204. Count Primes

 

注:质数从2开始,2、3……

 

改进过程:

一、常规思路是对小于n的每一个数进行isPrime判断,isPrime(int x)函数中for(int i = 2; i <= x /2; ++i),如果x%i==0,return false。

二、将isPrime(int x)中i的范围改为i * i <= x。不用i <= sqrt(x),因为sqrt耗时。

三、isPrime中把是2、3、5倍数的数直接return,不进入for循环。

四、对于每一个数p,p2、p2+p、p2+2p……均不为素数,有点像动态规划的思想。此时可以不用isPrime(int x)函数,而是维护一个isPrime[n]的bool数组,先设里面所有的值均为true,然后i从3开始循环(对应的是如果输入n<3,直接return 0)。因为会把i2之后的一系列数在isPrime数组中的值变为false,因此i循环至i * i < n。

关于if(!isPrime[i]) continue;这一句解释一下。如果isPrime[i] == false,那么也就是说在之前的i循环里被标记过了。设之前的循环的数为p,那么 i = p+ np,如果没有continue这一句的话,那么 j = i * i,设j也等于p2 + mp,于是得到等式 (p+ np)2 = p+ mp,解得m = p((p + n)2 - 1),也就是说j之前在p循环时已经被标记过了,因此可以直接continue,节省时间。以下是代码,也是题目提示中给出的最优代码。

 1 public int countPrimes(int n) {
 2    boolean[] isPrime = new boolean[n];
 3    for (int i = 2; i < n; i++) {
 4       isPrime[i] = true;
 5    }
 6    // Loop's ending condition is i * i < n instead of i < sqrt(n)
 7    // to avoid repeatedly calling an expensive function sqrt().
 8    for (int i = 2; i * i < n; i++) {
 9       if (!isPrime[i]) continue;
10       for (int j = i * i; j < n; j += i) {
11          isPrime[j] = false;
12       }
13    }
14    int count = 0;
15    for (int i = 2; i < n; i++) {
16       if (isPrime[i]) count++;
17    }
18    return count;
19 }

五、在最后计算cnt时,从2开始到n-1都被判断了一遍,但是偶数绝对不是素数,因此是没必要访问其在数组isPrime中的值的。

既然计算cnt时可以跳过偶数,那么在之前的标记isPrime的for循环里,也可以跳过偶数,相应的j每次+= 2 * i,因为p(p + 1)必定为偶数。

所以for循环里依次变为i += 2, j += 2 * i, i += 2(上一步为++i, j += i, ++i)。

 

最终版代码

 1 class Solution {
 2 public:
 3     int countPrimes(int n) {
 4         if(n < 3) return 0;
 5         bool* isPrime = new bool [n];
 6         for(int i = 3; i < n; ++i)
 7             isPrime[i] = true;
 8             
 9         for(int i = 3; i * i <= n; i += 2){
10             if(!isPrime[i]) continue;
11             for(int j = i * i; j < n; j += 2 * i)
12                 isPrime[j] = false;
13         }
14         
15         int cnt = 1;
16         cout<<isPrime[9]<<endl;
17         for(int i = 3; i < n; i += 2){
18             if(isPrime[i]) ++cnt;
19         }
20         return cnt;
21     }
22 };

 

posted @ 2016-03-20 16:32  co0oder  阅读(209)  评论(0编辑  收藏  举报