计算质数

求数字n之前所有的质数。

转自:https://blog.csdn.net/awq520tt1314/article/details/77141347

埃拉托色尼筛选法:

(1)先把1删除(现今数学界1既不是质数也不是合数)

2)读取队列中当前最小的数2,然后把2的倍数删去

3)读取队列中当前最小的数3,然后把3的倍数删去

4)读取队列中当前最小的数5,然后把5的倍数删去

5)如上所述直到需求的范围内所有的数均删除或读取(即某个素数的平方等于最后一个数


[java]  view plain  copy
  1. public class Solution {  
  2.     public int countPrimes(int n) {  
  3.         if(n == 0 || n == 1return 0;  
  4.           
  5.         boolean[] notprime = new boolean[n];  
  6.         // 默认所有的元素值都会设置成false; boolean的初始值为false  
  7.         notprime[0] = true;  
  8.         notprime[1] = true;  
  9.       //前两个数都不是素数  
  10.           
  11.         for(int i = 2; i * i < n; i++){  //当某个素数的平方等于或者大于n的时候,判断结束  
  12.             if(!notprime[i]){ //如果I是素数,那么  
  13.                 for(int j = 2; i * j < n; j++){   
  14.                     notprime[i*j] = true;  
  15.                 }  
  16.             }  
  17.         }  
  18.           
  19.         int count = 0;  
  20.         for(boolean notP : notprime){  
  21.             if(!notP) count++;  
  22.         }  
  23.           
  24.         return count;  
  25.           
  26.     }  
  27. }  

跑下来其实效率也不是很高,后面我发现有重复的地方:

[java]  view plain  copy
  1. <span style="font-family:'Songti SC';"for(int i = 2; i * i < n; i++){  
  2.             if(!notprime[i]){   
  3.                 for(int j = 2; i * j < n; j++){ //这里有大量的数字重复,比如当i=2时候,j =2,3,...;当i=3是,j= 2,3,..  
  4.                     notprime[i*j] = true//此时2*3在i = 2时候已经判断过; </span><span style="font-family:'Songti SC';">i = 3没有必要再判断。</span><span style="font-family:'Songti SC';">  
  5.                 }  
  6.             }  
  7.         }  
  8.         </span>  

改正为:


[java]  view plain  copy
  1. for(int i = 2; i * i < n; i++){    
  2.            if(!notprime[i]){   
  3.                for(int j = i; i * j < n; j++){   
  4.                    notprime[i*j] = true;  
  5.                }  
  6.            }  
  7.        }  

另一种写法:

class Solution
{
    public int countPrimes(int n)
    {
        if(n<2) {
            return 0;
        }
        boolean[] flag=new boolean[n];
        for(int i=0;i<n;i++) {
            flag[i]=true;
        }
        flag[0]=false;
        flag[1]=false;
        int num=0;
        for(int i=2;i<n;i++){
            if(flag[i]) {
                for(int j=2;i*j<n;j++){
                    flag[i*j]=false;
                }
            }
        }
        for(int i=0;i<n;i++)
        {
            if (flag[i])
            {
                num++;
            }
        }
        return num;
    }
}

对于每个素数k,算法将primes[k*i]设置为false。 

在for循环中执行了n/k-k+1次 
因此,时间复杂度
T(n)=n/2-2+1+n/3-3+1+n/5-5+1.....
    =O(n/2+n/3+n/5+.....)
    <O(nπ(n))
    =O(n*根号n/logn)

ps:π(n)表示小于或等于n的素数的个数; 
这里的上限时间复杂度是非常松散的,实际的时间复杂度比它好很多。

猜你喜欢

转载自blog.csdn.net/yanhanwen123/article/details/80564965