算法题分享 | 计数质数

59 阅读2分钟

此去经年,眉目成书🌋_6_蘅皋暮_来自小红书网页版.jpg

题目

给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。

示例 1:

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

示例 2:

输入: n = 0
输出: 0

示例 3:

输入: n = 1
输出:0

提示:

  • 0 <= n <= 5 * 106

题解

解题思路

本题可以使用暴力枚举的解法,代码也很容易实现,缺点是时间复杂度较大,尤其是处理大数的时候,在很多 OJ 系统都会超时。所以这里着重介绍一个常见的算法,该算法由希腊数学家厄拉多塞(Eratosthenes)提出,称为厄拉多塞筛法,简称埃氏筛。

一个质数 x,其的倍数(2x、3x、4x...)一定是合数,可以借助一个数组 isPrimes 存储 2 ~ n-1 各个数字是否是质数, 当一个数 x 被判断为质数,同时将其的倍数(2x、3x、....) 都标记为合数。

这样一来,在处理每个数时,直接通过 isPrimes 数组即可判断是否是质数,因为,如果是合数,那么一定会在处理前面的元素时就做了标记。

此外,还可以进一步提高效率,在处理质数 x 时,没有必要从 2x 开始把倍数标记为合数,而是应该从 x*x 开始,这是因为 2x ~ (x-1)*x 肯定在处理前面的数时已经被标记了,例如处理 2 时,由于 2x 是 2 的倍数,因此会将其标记为合数。

这种算法利用了数和数之间的联系,提供判断的效率,而不是每个数都枚举一遍。

代码

class Solution {
    public int countPrimes(int n) {
        
        int ans = 0;

        int[] isPrimes = new int[n];
        Arrays.fill(isPrimes, 1);

        for (int x = 2; x < n; x++) {
            if (isPrimes[x] == 1) {
                ans++;

                if (x * x < n) {
                    for (long i = (long)x * x; i < n; i += x) {
                        isPrimes[(int)i] = 0;
                    }
                }
            }
        }

        return ans;
    }
}

复杂度分析

  • 时间复杂度:O(nloglogn)\

  • 空间复杂度:O(n)

优质项目推荐

推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。

lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体

公众号

有兴趣可以关注公众号一起学习更多的干货哈!

扫码_搜索联合传播样式-白色版.png