力扣题目204. 计数质数

本文介绍了一种高效计算小于给定整数n的所有质数数量的方法。通过逐步优化,从简单的遍历检查到采用埃氏筛法,显著降低了时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:给定整数 n ,返回 所有小于非负整数 n 的质数的数量

示例 1:

输入:n = 10
输出:4
解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:

输入:n = 0
输出:0
示例 3:

输入:n = 1
输出:0

所谓质数也叫做素数,即除了1没有其他的可以整除的自然数。所以我们可以想到遍历得到答案。

class Solution {
public:
    int countPrimes(int n) {
        int ans = 0;  //记录质数的个数
        for(int i = 2;i <= n;i++){
            int j = 2;
            for(;j < i;j++){
                if(i % j == 0){
                    break;
                }
            }
            if(j == i){
                ans++; // 若比i小的自然数没有可以被整除的就表明为质数。
            }
        }
        return ans;
    }
};

         但这个方法时间复杂度较高,为O(n²);我们需要对其进行优化,比如,可以简单举一个例子,如果n = 64 的话,在我们判断是否有可以整除的自然数的时候,我们不用遍历到n,我们遍历到\sqrt{n}即可,即遍历到8即可。原因是,大于8之后,如果i可以被64整除的话,那个64/i的结果肯定是小于8的一个自然数,那么我们肯定会在8之前就可以遍历到。即我们对于一个自然数n是否为质数,我们遍历到\sqrt{n}即可。故我们可以把代码修改成以下情况:

class Solution {
public:
    int countPrimes(int n) {
        int ans = 0;  //记录质数的个数
        for(int i = 2;i <= n;i++){
            int j = 2;
            for(;j * j <= i;j++){
                if(i % j == 0){
                    break;
                }
            }
            if(j * j > i){
                ans++; // 若比i小的自然数没有可以被整除的就表明为质数。
            }
        }
        return ans;
    }
};

 即使这样,时间复杂度为O(n\sqrt{n}),提交仍然超时。经过学习,我们学习到了一种新算法——埃氏筛。这个算法的主要思想是,从小到大进行遍历,每次遍历的时候,对其倍数进行标记,然后根据它是否标记来来判断是否需要进行遍历,减小遍历的次数。例如我们遍历2,对2的倍数进行标记即对4,6,8进行标记。到4的时候就不需要遍历,因为4的倍数也是2的倍数无需重复遍历,即减少了遍历次数。具体看以下代码:

class Solution {
public:
    int countPrimes(int n) {
        int ans = 0;  //记录质数的个数
        vector<int>sign(n + 1,1);//标记数组
        for(int i = 2;i <= n;i++){
            if(sign[i] == 1){ //对没有标记的元素进行遍历
                for(int j = i + i;j <= n;j += i){
                    sign[j] = 0;//因为j是i的倍数,故j必不是质数
                }
            }
        }
        for(int i = 2;i < n;i++){ //对没有标记的元素进行统计
            if(sign[i] == 1){
                ans++;
            }
        }
        return ans;
    }
};

 这个方法的时间复杂度为O(nloglogn),可通过。我认为以上方法是新手小白可以接受的方法。当然还有其他更好的方法,如线性筛等。作者也是新手小白,故不做赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值