求数字n之前所有的质数。
转自:https://blog.csdn.net/awq520tt1314/article/details/77141347
埃拉托色尼筛选法:
(1)先把1删除(现今数学界1既不是质数也不是合数)
(2)读取队列中当前最小的数2,然后把2的倍数删去
(3)读取队列中当前最小的数3,然后把3的倍数删去
(4)读取队列中当前最小的数5,然后把5的倍数删去
(5)如上所述直到需求的范围内所有的数均删除或读取(即某个素数的平方等于最后一个数)
- public class Solution {
- public int countPrimes(int n) {
- if(n == 0 || n == 1) return 0;
- boolean[] notprime = new boolean[n];
- // 默认所有的元素值都会设置成false; boolean的初始值为false
- notprime[0] = true;
- notprime[1] = true;
- //前两个数都不是素数
- for(int i = 2; i * i < n; i++){ //当某个素数的平方等于或者大于n的时候,判断结束
- if(!notprime[i]){ //如果I是素数,那么
- for(int j = 2; i * j < n; j++){
- notprime[i*j] = true;
- }
- }
- }
- int count = 0;
- for(boolean notP : notprime){
- if(!notP) count++;
- }
- return count;
- }
- }
跑下来其实效率也不是很高,后面我发现有重复的地方:
- <span style="font-family:'Songti SC';"> for(int i = 2; i * i < n; i++){
- if(!notprime[i]){
- for(int j = 2; i * j < n; j++){ //这里有大量的数字重复,比如当i=2时候,j =2,3,...;当i=3是,j= 2,3,..
- notprime[i*j] = true; //此时2*3在i = 2时候已经判断过; </span><span style="font-family:'Songti SC';">i = 3没有必要再判断。</span><span style="font-family:'Songti SC';">
- }
- }
- }
- </span>
改正为:
- for(int i = 2; i * i < n; i++){
- if(!notprime[i]){
- for(int j = i; i * j < n; j++){
- notprime[i*j] = true;
- }
- }
- }
另一种写法:
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的素数的个数;
这里的上限时间复杂度是非常松散的,实际的时间复杂度比它好很多。