您的位置:首页 > 其它

LeetCode 204. Count Primes

2016-03-20 16:32 429 查看


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

改进过程:

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

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

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

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

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

publicintcountPrimes(intn){
boolean[]isPrime=newboolean
;
for(inti=2;i<n;i++){
isPrime[i]=true;
}
//Loop'sendingconditionisi*i<ninsteadofi<sqrt(n)
//toavoidrepeatedlycallinganexpensivefunctionsqrt().
for(inti=2;i*i<n;i++){
if(!isPrime[i])continue;
for(intj=i*i;j<n;j+=i){
isPrime[j]=false;
}
}
intcount=0;
for(inti=2;i<n;i++){
if(isPrime[i])count++;
}
returncount;
}


五、在最后计算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)。

最终版代码

classSolution{
public:
intcountPrimes(intn){
if(n<3)return0;
bool*isPrime=newbool
;
for(inti=3;i<n;++i)
isPrime[i]=true;

for(inti=3;i*i<=n;i+=2){
if(!isPrime[i])continue;
for(intj=i*i;j<n;j+=2*i)
isPrime[j]=false;
}

intcnt=1;
cout<<isPrime[9]<<endl;
for(inti=3;i<n;i+=2){
if(isPrime[i])++cnt;
}
returncnt;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: