Leetcode-204:计数质数 (各种解法详解)

目录

题目链接

题目

示例

提示

思路

1. 暴力枚举法

2. 埃氏筛法


题目链接

https://leetcode-cn.com/problems/count-primes/

题目

统计所有小于非负整数 n 的质数的数量。(注意,这里说的是<n,不包括n)

示例

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

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

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

提示

  •  0\leq n\leq 5*10^{6}

思路

1. 暴力枚举法

这题其实相信很多人在学C/C++课的时候都做过,最简单的方法就是暴力枚举

通过两层for循环对每个数是否是素数进行判断,第一层for从2开始遍历每个数,第二层for判断这个数是不是是不是质数。

判断方法也很简单,把这个数x分别与\left [ 2,\sqrt{x}\right ]之间的每个数取余看余数是否为0即可。

那么为什么到\sqrt{x}即可呢?  

因为如果 y 是 x 的一个因数,那么\frac{x}{y}必然也是 x 的因数,因此我们只要判断 y 和 \frac{x}{y} 中更小的那个数即可,也就是说如果在\left ( \sqrt{x},x\right ]区间存在一个因素的话,其对应的另一个因数必然在\left [ 2,\sqrt{x}\right ]区间,因此我们只要在前面这个区间判断即可,也就不需要对所有的数进行判断。

举个例子:拿36来说,它的因数是2,3,4,6,9,12,18,即2*18,3*12,4*9,6*6,12是它的质数,那么肯定也存在一个\leqslant \sqrt{36}=6的数与之对应,即3。

暴力枚举的代码如下:

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

    int countPrimes(int n) {
        int ans = 0;
        for (int i = 2; i < n; ++i) {
            ans += isPrime(i);
        }
        return ans;
    }
};

那么问题来了,在Leetcode提交时超时了,暴力枚举的时间复杂度高达 O(n\sqrt{n})

这里,我们介绍一种很有意思的算法,由希腊数学家厄拉多塞(Eratosthenes)提出的厄拉多塞筛法,简称埃氏筛法

2. 埃氏筛法

埃氏筛法原理很简单,如果x是一个质数,那么2x、3x、4x...一定不是质数,比如3是一个质数,那么6、9、12...一定是质数,如下图所示(图源:magicalchao):



​基于以上思想,就可以省去大量的取余运行,节省大量时间,代码如下:

int countPrimes(int n) {
    int count = 0;
    vector<bool> signs(n, true);//初始化一个大小为n的bool数组,默认所有的数都是质数
    for (int i = 2; i < n; i++) { //从2开始遍历每个数,1不参与遍历,也不会计入count
        if (signs[i]) {  //判断当前遍历的数时候为质数,如果不是质数就遍历下一个数
            count++;    //计数器,统计质数个数
            for (int j = i + i; j < n; j += i) { //排除当前这个质数的2n、3n倍数....
                signs[j] = false;
            }
        }
    }
    return count;
}

 

 对于以上解法,仔细观察我们会发现,这个算法还有优化空间,比如对于15这个数,即是3的倍数也是5的倍数,当我们遍历到3的时候已经将15判断为了fasle,不是质数,而当遍历到5的时候,又重复判断了一遍,造成了冗余,对于以上问题,可以采用线性筛的方法。

此外,我们定义signs数组采用的是bool型,这将造成存储空间的浪费,有一种解决方案是采用比特表(Bitmap)算法进行处理,对于上面两种算法下次再更,掌握了埃氏筛的思想,也已经比暴力枚举好多了。

———————————————————未完待续————————————————————

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值