个人笔记(计数质数的方法)

题:统计所有小于非负整数 n 的质数的数量。

1.枚举法

双重循环进行遍历,第一重遍历n,第二重判断n是否为素数,时间复杂度 o ( n n ) o(n\sqrt{n}) o(nn ),空间复杂度为o(1).

int countPrimes(int n) {
        int ans = 0;
        int flag;
        for (int i = 2; i < n; ++i) {
            flag = 1;
            for(int j = 2; j < int(sqrt(i)) + 1; j++)
            {
            	if(i % j == 0)
            	{
            		flag = 0;
            		break;
            	}
            }
            if(flag)
            {
            	ans++;
            }
        }
        return ans;
}

2.埃氏筛

开一个长度为n的bool型数组isprime,第i位表示整数i是否为素数,初始化化为true,从2开始遍历,如果遇到一个数x为素数,计数值加1,则将isprime数组下标为 2 x , 3 x , 4 x … … k x ( k x < n < = k x + x ) 2x,3x,4x……kx(kx2x,3x,4xkxkx<n<=kx+x的值置为false。当然其也可以优化,因为 2 x , 3 x 2x,3x 2x,3x等,会由前面的素数进行更新,只需要从 x ∗ x , ( x + 1 ) ∗ x . . . . . x*x,(x+1)*x..... xx,(x+1)x.....开始更新及可。
时间复杂度: o ( n l o g l o g ( n ) ) o(nloglog(n)) o(nloglog(n))(具体怎么计算我也不太了解),空间复杂度 o ( n ) o(n) o(n).

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

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/count-primes/solution/ji-shu-zhi-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.线性筛

埃氏筛也存在重复计算的情况,对于6, x = 2 x=2 x=2 x = 3 x=3 x=3时均对其进行了一次运算,导致了时间的浪费。我们考虑对于每一个合数只进行计算一次,使时间复杂度降到线性。对于任意一个合数x,我们能写成 x = p y x=py x=py的形式,其中p为x的最小素因子,我们只在遍历到y时,通过素数p对其进行一次操作。仍然从2开始到n进行遍历,如果isprime是true,将其加入prime容器,然后将对于当前所遍历到的i,在其中,我们用j遍历prime容器,将 i ∗ p r i m e [ j ] i*prime[j] iprime[j]置为false,当遇到i可以被 p r i m e [ k ] prime[k] prime[k]整除,即 i = p r i m e [ k ] ∗ t i=prime[k] * t i=prime[k]t的形式时退出,因为对于prime之后的素数来说 i ∗ p r i m e [ j ] ( j > k ) i*prime[j](j>k) iprime[j](j>k)不应由 p r i m e [ j ] prime[j] prime[j]更新,而在遍历到 p r i m e [ j ] ∗ t prime[j]*t prime[j]t时由 p r i m e [ k ] prime[k] prime[k]更新(因为 i ∗ p r i m e [ j ] = p r i m e [ k ] ∗ t ∗ p r i m e [ j ] i*prime[j]=prime[k] * t*prime[j] iprime[j]=prime[k]tprime[j],而 p r i m e [ k ] < p r i m e [ j ] prime[k]prime[k]<prime[j],由最小的素数更新)。

int countPrimes(int n) {
        vector<int>prime;
        bool *flag = new bool[n];//flag即为isprime
        memset(flag,1,n*sizeof(bool));//初始化
        for(int i = 2; i < n; i++)
        {
            if(flag[i])
            {
                prime.push_back(i);
            }
            for(int j = 0; j < prime.size() && i * prime[j] < n; j++)
            {
                flag[prime[j]*i] = false;
                if(i  % prime[j] ==0)
                {
                    break;
                }
            }
        }
        return prime.size();
    }

你可能感兴趣的:(笔记,枚举类,素数筛)