本文主要是介绍[数学]204. 计数质数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
统计所有小于非负整数 n
的质数的数量。
示例 1:
输入:n = 10 输出:4 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。
示例 2:
输入:n = 1 输出:0
提示:
0 <= n <= 5 * 10^6
方法:
(1)平方根枚举,超时
(2)埃氏筛
枚举没有考虑到数与数的关联性,因此难以再继续优化时间复杂度。接下来我们介绍一个常见的算法,该算法由希腊数学家厄拉多塞(EratosthenesEratosthenes)提出,称为厄拉多塞筛法,简称埃氏筛。
我们考虑这样一个事实:如果 x 是质数,那么大于 x 的 x 的倍数 2x,3x,… 一定不是质数,因此我们可以从这里入手。
我们设 isPrime[i] 表示数 i 是不是质数,如果是质数则为 1,否则为 0。从小到大遍历每个数,如果这个数为质数,则将其所有的倍数都标记为合数(除了该质数本身),即 0,这样在运行结束的时候我们即能知道质数的个数。
当然这里还可以继续优化,对于一个质数 x,如果按上文说的我们从 2x 开始标记其实是冗余的,应该直接从 x⋅x 开始标记,因为 2x,3x,… 这些数一定在 x 之前就被其他数的倍数标记过了,例如 2 的所有倍数,3 的所有倍数等。
代码:
// 204. 计数质数
static void test_204() {//int n = 1;//int n = 10;int n = 5000000;int ret = countPrimes(n);System.out.println("ret:" + ret);
}
//n = 5000000时超时
/*
static int countPrimes(int n) {int ans = 0;for (int i = 0; i < n; i++) {if (isPrime(i)) {//System.out.println("Prime i:" + i);ans++;}}return ans;
}
static boolean isPrime(int n) {if (n == 0 || n == 1) {return false;}double x = Math.sqrt(n);for (int i = 2; i <= (int)x; i++) {if (n%i == 0) {return false;}}return true;
}
*/
static int countPrimes(int n) {int ans = 0;int[] isPrime = new int[n];Arrays.fill(isPrime, 1);// 0,1不是质数直接排除for (int i = 2; i < n; i++) {if (isPrime[i] == 1) {ans++;// 质数的倍数排除掉/** (long)i * i* 将i的类型转换为long类型,之后相乘是long类型相乘* (long)(i * i)* 将i*i的结果转换为long类型,之后相乘是int类型相乘,此时可能已经发生溢出* */if ((long)i * i < n) {for (int j = i * i;j < n; j+=i) {isPrime[j] = 0;}}}}return ans;
}
这篇关于[数学]204. 计数质数的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!