Project Euler - 问题 3:如何使我的 Eratosthenes 筛实施正常工作?

Posted

技术标签:

【中文标题】Project Euler - 问题 3:如何使我的 Eratosthenes 筛实施正常工作?【英文标题】:Project Euler - Problem 3: How to make my Sieve of Eratosthenes implementation work properly? 【发布时间】:2022-01-08 16:41:41 【问题描述】:

所以我正在尝试解决 Project Euler 的第三个问题,在这个问题中你必须得到一个数的最大素因数。我正在尝试这个问题via freeCodeCamp。我通过了 2、3、5、7、8 和 13195 的所有测试,但从 13195 及以上我收到了 Potential infinite loop detected on line 12. Tests may fail if this is not changed. 警告。 600851475143 的最终测试给出以下警告:

Potential infinite loop detected on line 6. Tests may fail if this is not changed.
Potential infinite loop detected on line 15. Tests may fail if this is not changed.
Potential infinite loop detected on line 12. Tests may fail if this is not changed.

还有 104441 的可怕错误答案。

我做错了什么,因为我的循环看起来不像它们会在语法方面无限运行?我在这里遗漏了什么吗?

我正在使用的代码:

const eratoSieve = (n) => 
  let primes = [2, 3, 5, 7];
  if (n > 7)
  
    primes = [];
    for (let i = 2; i <= Math.sqrt(n); i++)
    
      primes.push(i);
    
  

  for (let j = 0; j < primes.length; j++)
  
    let currentMultiple = primes[j];
    for (let k = j + 1; k < primes.length; k++)
    
      if (primes[k] % currentMultiple === 0)
      
        primes[k] = false;
      
    
  
  primes = primes.filter(elem => elem != false);
  return primes;
;

function largestPrimeFactor(number) 
  let primeNums = eratoSieve(number);
  console.log(primeNums);
  let biggestPrime = 0;
  primeNums.forEach(elem => 
    (number % elem === 0) ? biggestPrime = elem : 0;
  );
  return biggestPrime;


console.log(largestPrimeFactor(13195));

提前感谢您的帮助!

【问题讨论】:

注意,这不是埃拉托色尼的筛子。是审判部门。真正的筛子不使用% 运算符,而且速度要快得多(但输入这么大仍然不切实际)。 另外,您还有一个错误,您会在每个 splice 之后跳过一个数字。经典的“在迭代期间删除元素”问题。 @user2357112supportsMonica 我确实删除了splice(在上面添加了我的代码的更新版本)并将其替换为primes[k] = false @user2357112supportsMonica。使用实际的筛子是not impractical here,因为我们最多只需要达到输入数字的平方根。 (而且我知道这个筛子的效率并不高,但这足以快速解决这个问题。) 【参考方案1】:

你不能做 6000 亿次循环。 假设每个数字仅占用 1 位存储空间(事实并非如此),那么仅您的代码的第一部分就会产生超过 70 GB 的数据。

您的方法在理论上可行,但对于如此大的数字而言效率太低,不实用。

这个问题的2个提示:

-你需要找到所有数的质因数,从下往上,你会先找到质数,然后再找到它的任何倍数。我们以数字 30 为例。

你发现 2 是一个因素。现在你知道 2x15 = 30。

你已经减少了问题,现在你有了一个数的质因数,只需要找到 15 的质因数。

任何 15 的素数因数也是 30 的素数因数。 现在让我们继续寻找。 3除以15得5。

同样的逻辑适用,你会在 9、12、15 等之前找到 3。所以你知道这个因子肯定是素数。

现在你又找到了一个素数。你现在知道 2x3x5 = 30。所以你现在可以检查 5,4 不除所以转到 5。

5 等于 5,你不能再进一步了。因此,该数的所有质因数都已找到。

对于任何数字,您都无法在 2 之前找到 4、6、8、10、12 作为因子。 -- 你总是会发现素数是它的倍数之前的一个因数 -- 素数的所有倍数都不是素数。它们本身可以分解为素数的乘积。 6 = 3x2。 8 = 2x2x2, 10 = 5x2, 12=3x2x2 等等。所以在执行此方法时,您只会得到素数。

6 是 30 的因数。但 6 = 3x2。 2 和 3 都是素数。并且都小于 6,因此会在 6 之前找到。

现在让我们考虑数字 40。

2x20 = 40。3 不等于 20。现在你到 4 就会发现问题。 4 本身不是素数,但被发现是 20 的因数,根据我之前解释的应该是素数。

我在这个解释中留下了一个疏忽,那就是素数的幂。 4 = 2x2 (2^2) 8=2x2x2 (2^3) 16 = 2x2x2x2 (2^4)。

-因子成对出现,只要找到一个因子,就会找到与之匹配的因子。您只需要检查一个数字的平方根即可找到它的所有因数。如果一个数的平方根之前没有找到任何因数,那么就没有必要再进一步了,这个数肯定是素数。

无论如何希望这会有所帮助

【讨论】:

好的,我改变了 eratoSieve 函数的第一部分,其中生成了数字并将其推入素数数组,使其仅上升到 n 的平方根。性能稍微好一点,我不再收到关于 13195 的警告,但最后一个案例仍然给出警告和相同的答案。请问您能否详细说明您给出的提示? 对不起,我知道这很模糊。

以上是关于Project Euler - 问题 3:如何使我的 Eratosthenes 筛实施正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

Project Euler #1 测试扩展

Project Euler:Problem 47 Distinct primes factors

Project Euler:Problem 77 Prime summations

用 Javascript 解决 Project Euler 16

欧拉计划(Euler Project)——第一题到第三题

Project Euler 99: Largest exponential