《算法零基础100讲》(第8讲) 素数筛选(C语言解题)

204.计算质数

在这里插入图片描述

  质数在之前的篇章中我们也进行过一个初步的了解,质数的定义是:只包含1和本身为因子的数就叫做质数,质数又称为素数。例如2,3,5,7,11等,他们的因子都只有两个,那就是1和他们本身。

  今天这道题我们是要计算出小于n的质数有多少个,大多数人第一想法就是遍历,当然这也是最直接,最方便的解法,思维方式也不算复杂,只需在区间[2,√n]中查询是否还有能够整除n的数,有则返回true,否则返回false。
代码如下:

bool isPrime(int n) {
    
                  
    int i, sqrtn = sqrt(n + 1e-6);
    if(n <= 1) {
    
    
        return false;                
    }
    for(i = 2; i <= sqrtn; ++i) {
    
    
        if(n % i == 0) {
    
             
            return false;
        }
    }
    return true;                   
}

int countPrimes(int n){
    
    
    int count = 0;
    for(int i = 2; i < n; i++){
    
    
		bool b = isPrime(i);
		if(b){
    
    
			count++;
		}
	}
    return count;
}

这种解法的时间复杂度是O(n√n),但这道题的数据范围是[0,5000001],如果用这种解法的话,计算时间还是有点大,会超出时间限制,所以接下来我们介绍另外一种解法——Eratosthenes法。

  我们定义一个数组dp[ ],其中dp[ i ]表示数字 i 是否是质数,如果 i 不是,则dp[ i ] = true。初始条件是dp[ 0 ] = dp[ 1 ] = true。
分析:

  1. 从未被标记的数中找到最小的数 i,i * 2,i * 3,i * 4 等2的倍数都标记为true,因为2为质数,所以2,4,6,8,10…都被标记为质数。
  2. 在从下一个最小未被标记的数3计算,6,9,12,15…标记为质数。
  3. 以此类推。

多举几个例子,我们可以发现每个i在计算之前,[1, i)的范围内都被上一个质数 i 给计算过。
如图:
在这里插入图片描述
所以我们只需从 [i ^ 2,n)的 区间范围内计算。

代码如下:

#define ll long long

bool dp[5000001];

int countPrimes(int n){
    
    
    if(n == 0 || n == 1){
    
    
        return 0;
    }
    int count = 0;
    dp[0] = dp[1] = false;
    for(int i = 2; i < n; i++){
    
    
        if(!dp[i]){
    
    
        	//若为被标记,则说明i为质数,count++
            count++;
            //对i的i * i倍进行标记
            for(ll j = (ll) i * i; j < n; j+=i){
    
    
                dp[j] = true;
            }
        }
    }
    return count;
}

猜你喜欢

转载自blog.csdn.net/qq_53060585/article/details/121027333