【问题标题】:Biggest prime number using sieve of Eratosthenes使用埃拉托色尼筛法的最大素数
【发布时间】:2021-06-05 23:41:57
【问题描述】:

我设法解决了问题,但我超过了时间限制。

要解决的问题:如果给定的数字 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

谢谢!

【问题讨论】:

  • 我投票结束这个问题,因为优化问题属于 codereview.SE

标签: javascript sieve-of-eratosthenes


【解决方案1】:

这里有很多优化要做 - 快速阅读这里 (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);
}

【讨论】:

    【解决方案2】:

    查看筛选代码时,我问自己的一个基本问题是:“此代码是否使用模 (%) 运算符?”如果是这样,它就不是埃拉托色尼筛。你正在做试验师,这要慢得多。现在分庭肯定有地方和理由,但是根据你的问题标题,你打算使用SoE。

    例如见Wikipedia pseudocode。唯一的操作是只涉及简单加法、测试和集合的两个循环。而已。没有乘法,没有除法,没有模数。这绝对是算法快速的关键。内循环也很快变得稀疏,因为增量不断变大,所以我们实际上运行内循环代码的次数越来越少。与您发布的初始代码相比,内部循环运行 更多 次。

    要进行基本的 SoE,您需要一个小数组,然后只需 4 行代码就可以进行筛选,外部循环转到 sqrt(n)。然后您可以检查仅标记素数的数组。在您的情况下,您可以向后走并在找到第一次出现时返回。有无数种优化方法,但是对于相对较小的 n(例如,在 10^9 以下,之后您确实需要进行分段 SoE),简单的基本 SoE 的速度之快令人惊讶。

    综上所述,您得到了工作代码,这是很好的第一步。一旦你有东西工作,尝试不同的方法会容易得多。

    【讨论】:

      猜你喜欢
      • 2013-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-16
      • 2017-11-14
      • 1970-01-01
      相关资源
      最近更新 更多