如何解决使用埃拉托色尼筛法的最大素数
我设法解决了问题,但超出了时间限制。
要解决的问题:如果给定的数字 n
非常大,则需要花费大量的时间。
const n = 126;
let lastPrime = 0;
for (let j = 2; j <= n; j++) {
let counter = 0;
for (let i = 1; i <= j; i++) {
if (j % i === 0) counter++;
}
if (counter === 2) lastPrime = j;
}
print(lastPrime); // Biggest prime number of 126 is 113
谢谢!
解决方法
这里有很多优化要做 - 在这里快速阅读 (https://math.stackexchange.com/questions/889712/the-fastest-way-to-count-prime-number-that-smaller-or-equal-n/893767) 会有所帮助。
但对于初学者来说,您可以更改代码中的一些内容以使其更快:
第 1 步:减少外部迭代次数,因为我们知道所有偶数都是非质数。
for (let j = 3; j <= n; j += 2) {
...
}
第 2 步:通过仅迭代最大数量的 Sqrt 来减少内循环。一旦我们找到一个因素,也要跳出内部循环。不需要迭代到最后。这两个将为您带来最大的胜利。
let prime = true;
for (let i = 2; i <= Math.sqrt(j); i++) {
if (j % i === 0) {
prime = false;
break;
}
}
if (prime) {
lastPrime = j;
}
第 3 步:停止计算 Math.sqrt(j),因为您已经知道先前的最大值。 sqrt 是一个(相对)昂贵的操作。我们可以通过使用以前的值来避免它。
let maxBound = 2;
let maxSquare = maxBound * maxBound;
for (let j = 3; j <= n; j += 2) {
if (maxSquare < j) {
maxBound++;
maxSquare = maxBound * maxBound;
}
for (let i = 2; i <= maxBound; i++) {
...
}
}
第 4 步:如果您只想要最大的质数,请向后循环并在找到一个质数后立即中断。
这是完成的程序,它应该比你的程序快大约 2 个数量级。请注意,虽然我为您的程序提供了一些微不足道的优化,但与您可以在此处找到的算法优化相比,这总是显得苍白无力:https://math.stackexchange.com/a/893767
function getMaxPrime(n) {
for (let j = n; j >= 3; j --) {
let prime = true;
for (let i = 2; i <= Math.sqrt(j); i++) {
if (j % i === 0) {
prime = false;
break;
}
}
if (prime) {
maxPrime = j;
break;
}
}
console.log(maxPrime);
}
,
我在查看筛选代码时问自己的一个基本问题是:“此代码是否使用模 (%) 运算符?”如果是这样,那就不是埃拉托色尼筛。你正在做试验部门,这要慢得多。现在试分肯定是有地方和原因的,但是根据你的问题标题,你打算使用SoE。
例如参见 Wikipedia pseudocode。唯一的操作是仅涉及简单加法、测试和集合的两个循环。而已。没有乘法,没有除法,没有模数。这绝对是算法运行速度快的关键。内循环也很快变得稀疏,因为增量不断变大,所以我们实际上运行内循环代码的次数越来越少。与您发布的初始代码形成对比,其中内循环运行 更多 次。
要进行基本的 SoE,您需要一个小数组,然后只需要 4 行代码来进行筛选,外层循环执行 sqrt(n)。然后你可以检查只剩下素数标记的数组。在您的情况下,您可以向后走并在找到第一次出现时返回。有无数的优化方法,但令人惊讶的是,对于相对较小的 n(例如,在 10^9 以下,您确实需要进行分段 SoE),简单的基本 SoE 的速度有多快。
综上所述,您获得了可工作的代码,这是一个很好的第一步。一旦某事起作用,尝试不同的方法会容易得多。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。