【问题标题】:Finding the smallest positive number that is evenly divisible by all of the numbers from 1 to 20? [duplicate]找到能被 1 到 20 的所有数字整除的最小正数? [复制]
【发布时间】:2017-05-29 00:34:44
【问题描述】:

这是一个 Project Euler 挑战,我试图找到能被 1 到 20 的所有数字整除的最小正数?

我想出的逻辑似乎运行得很慢。它已经运行了最后 4 分钟,但仍然没有找到号码。我试图弄清楚a)这个逻辑正确吗? b) 为什么这需要这么长时间? c) 有人可以给我一个关于更有效的替代逻辑的提示吗?

# 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
# What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
smallest_num = 2520
while smallest_num >= 2520:
    divisor = 2
    while smallest_num % divisor == 0 and divisor < 21:
        print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
        divisor += 1
    smallest_num += 1
print("Smallest number is: {}").format(smallest_num)

这仍在处理中,到目前为止我的终端看起来像这样

【问题讨论】:

  • 这段代码将永远运行。
  • 您可以优化它,使其不会检查 1 到 20 之间的每个数字。例如,通过检查 20,您也检查了 1、2、4、5 和 10。跨度>
  • while smallest_num &gt;= 2520: 没有理由停下来,所以不,你的逻辑不正确。此外,您获得 2520 的原因是您可以首先在较小的问题上测试您的逻辑。尝试编写一个不包含 2520 的程序,但在考虑 1 到 10 的数字时会产生 2520 作为输出。
  • 对于编程循环,通常最好手动写出前几次迭代中变量会发生什么。这通常可以诊断出循环是否会停止或实现其目标的问题
  • 您正在寻找最小公倍数,而这种蛮力方法是最糟糕的方法。你想做的是素数分解。 en.wikipedia.org/wiki/Least_common_multiple 或者使用欧几里得算法,找到GCD并做一些除法。

标签: python


【解决方案1】:

这是您的方法“正确”运行(随意使用该术语),但正如@James 所说,它会花费大量时间作为循环。

divisors = np.arange(1, 21)
num = 2520
while True:
    if np.all(num % divisors == 0):
        print(num)
        break
    num += 1

更好的方法(对于 Python 3.x)。直接来自类似question

import functools
import math

functools.reduce(lambda x,y: x*y//math.gcd(x, y), range(1, 21))
Out[27]: 232792560

【讨论】:

    【解决方案2】:

    以下代码可以正常工作。

    #!/usr/bin/env python
    import math
    
    #Generating primes
    divisorMax = 20;
    
    top = divisorMax + 1 #divisor max is the upper limit
    
    p = [x for x in range(2,top)]
    
    for num in p:
      for idx in range(2,(top//num)+1):
        if num*idx in p:
          p.remove(num*idx)
    
    #Solving the problem
    result = 1;
    
    for i in range(0, len(p)):
        a = math.floor(math.log(divisorMax) / math.log(p[i]));
        result = result * (p[i]**a);
    
    print(result)
    

    你正在使用蛮力技术来计算数字,这很容易理解和编写,但需要很长时间。

    我正在使用 质因数分解 技术解释 here

    【讨论】:

      【解决方案3】:

      我不是 100% 确定我的解决方案是否真的正确,但我想它是正确的,而且速度非常快。

      首先,我们不需要关心所有除数,因为大多数都是彼此的倍数。所以最好的方法是倒数除数,例如从 20 到 1。

      我看过素数,解需要是10以上所有素数的倍数,另外我们需要检查20除数,其余的可以忽略,因为在测试除数18时,9会起作用等等。

      所以我乘以 11 * 13 * 17 * 19 * 20。结果是 923780 并且至少可以被素数 + 20 整除。

      所以我会从 923780 开始,只测试每个第 923780 个数字。

      smallest_num = 923780
      steps = 923780
      while True:
          divisor = 19
          while smallest_num % divisor == 0 and divisor > 10:
              print("Smalles num = {} and Divisor = {}").format(smallest_num, divisor)
              divisor -= 1
          if divisor == 10:
              print("Smallest number is: {}").format(smallest_num)
              break
          smallest_num += steps
      

      也许我有逻辑错误?!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-30
        • 1970-01-01
        • 2018-04-10
        • 1970-01-01
        相关资源
        最近更新 更多