204. 计数质数

题目

寻找[2,n]的质数是很常见的问题,主要有三种方法,现总结如下:

枚举法

枚举法思路简单,但是要注意这几点:
1、0和1应该要特判,除非在判断质数时压根就不让0,1参与选择,直接从2开始
2、为了判断n是否是质数,只需要枚举i=2至i=根号n,但是在程序中应该表现为i*i <= n,素数条件如果从i*i<=x改为i<=sqrt(x)就过不了,因为sqrt函数运行速度很慢

class Solution {
public:
    int countPrimes(int n) {
        int num = 0;
        for(int i = 2;i < n;i++)
            if(isPrime(i))
                num++;
        return num;
    }
    bool isPrime(int n){
        for(int i = 2;i*i <= n;i++)
            if(n % i == 0)
                return false;
        return true;
    }
};

埃氏筛

埃氏筛的原理是,如果i是一个质数,那么i的整数倍一定是合数,我们使用一个数组来表示[2,n]质合数情况,逐个筛查。但是需要注意的是:
1、i*i可能会越过int的界,但是n一定是int,因此我们要在进入筛查之前就判断i*in的大小关系
runtime error: signed integer overflow: 46349 * 46349 cannot be represented in type 'int' (solution.cpp)
2、我们在标记质数时,不能够每次都从2*i开始标记,这样会浪费时间,造成冗余。因为这些合数在之前就已经标记过了,我们只需要从i*i开始标记即可。

class Solution {
public:
    int countPrimes(int n) {
        int num = 0;
        vector<int> prime(n,1);
        for(int i = 2;i < n;i++){
            if(prime[i])
            {   num++;
                if((long long)i*i < n)
                    for(long long j = i*i;j < n;j+=i)
                        prime[j] = 0;
            }
        }
        return num;
    }
    
};

线性筛

线性筛在埃氏筛的基础上更进一步,对于埃氏筛来说,45将被3和5标记两次,造成冗余。线性筛的思路是,将标记出来的质数存储在一个数组中,然后用[2,n]每个数去乘所有的质数,所得的积一定是合数。(注意不要越界)

class Solution {
public:
    int countPrimes(int n) {
        vector<int> isprime(n,1);
        vector<int> prime;
        for(int i = 2;i < n;i++){
            if(isprime[i]){
                prime.push_back(i);
            }
            for(int j = 0;j < prime.size()&&i*prime[j] < n;j++){
                isprime[i*prime[j]] = 0;
                if(i % prime[j] == 0)
                    break;
                }
            

        }
        return prime.size();
    }
};
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 自定义皮肤 设计师:戎码关山 返回首页