【问题标题】:what is the mathematical logic of this solution (finding a number that is a multiple of numbers 1 to 20)这个解决方案的数学逻辑是什么(找到一个数字是 1 到 20 的倍数)
【发布时间】:2018-08-11 18:10:43
【问题描述】:

2520 是可以除以 1 到 10 的每个数字而没有余数的最小数字。

能被 1 到 20 的所有数整除的最小正数是多少?

我已经找到了解决方案,但它几乎是暴力破解,运行大约需要 7 秒才能找到解决方案。

我在 stackoverflow 上找到了答案,但无法理解找到答案背后的逻辑。我知道 LCM 和 GCM 是什么,但他是如何想出以这种方式使用它们来找到答案的? (即 232,792,560)

def find_multiple
  lcm = 1

  (2..20).each do |i|
    lcm *= i / gcd(lcm, i)
  end

  lcm
end

def gcd(a, b)
  while b > 0
    a %= b
    return b if a == 0
    b %= a
  end

  a
end

puts find_multiple

【问题讨论】:

    标签: ruby


    【解决方案1】:

    更短的方法,使用 Integer 的内置 lcm 方法

    p (2..20).inject(&:lcm)  # => 232792560
    

    “lcm”的意思是“最小公倍数”。 (刷新你的记忆:lcm 在加减不同分母的分数时很有用)。上面的代码是对以下过程进行编码的一种非常简洁的方式:

    • 取2和3,计算lcm,即6。
    • 有了这个 6,计算 lcm 的下一个数字是 4。结果是 12。
    • 计算 lcm 12 和 5。结果 60
    • 计算 60 和 6 的 lcm。结果 60
    • 等。一直到 20

    【讨论】:

    • 您能否更详细地解释一下,我的问题的目标是了解找到答案背后的逻辑,而不一定是答案本身,我已经在网上找到了与您的答案完全相同的答案。不过还是谢谢
    • @aimenalt 添加了解释。
    【解决方案2】:

    每个非负整数都可以用它的素数分解来表示。因此,每个可以被220之间的所有数字整除的数字都可以表示

    2**n2 * 3**n3 * 5**n5 * 7**n7 * 11**n11 * 13**n13 * 17**n17 * 19**n19
    

    235711131719220 的值之间的质数,指数有待确定。

    Ruby 提供了一个方法Prime::prime_division,它返回一个数字的素数分解。让我们计算220 之间每个数字的素数分解:

    (2..20).each { |n| puts "#{n}: #{Prime.prime_division(n)}" }
     2: [[2, 1]]
     3: [        [3, 1]]
     4: [[2, 2]]
     5: [                [5, 1]]
     6: [[2, 1], [3, 1]]
     7: [                        [7, 1]]
     8: [[2, 3]]
     9: [        [3, 2]]
    10: [[2, 1],         [5, 1]]
    11: [                                [11, 1]]
    12: [[2, 2], [3, 1]]
    13: [                                         [13, 1]]
    14: [[2, 1],                 [7, 1]]
    15: [[3, 1],         [5, 1]]
    16: [[2, 4]]
    17: [                                                  [17, 1]]
    18: [[2, 1], [3, 2]]
    19: [                                                           [19, 1]]
    20: [[2, 2],         [5, 1]]
    

    12,例如等于2**2 * 3**1,表示为[2,2], [3,1]。每个二元组的形式为[p,e],其中p 是质数,e 是指数。

    现在考虑220 之间的每个素数。我们看到每个偶数都需要将2 提高到一个幂,其中最大值是4,对于16.that 这告诉我们每个数字n 可以被2 和@987654353 之间的每个数字整除@ 必须能被 2**4 整除。如果n能被2**4整除,当然也能被2**12**22**3整除,从而满足220之间所有其他偶数的要求。由此可见,上述表达式中的n2 必须至少为4。由于我们想要最小的素数乘积的幂,我们将n2 设置为4

    对于素数3。对于220 之间的五个数字,可以被3 整除的指数为11212。所有能被220 之间的所有数字整除的数字因此必须能被3**2 整除。因此,我们将n3 设置为2

    对剩余的每个素数 5711131719 重复此操作,我们看到可被 220等于

    2**4 * 3**2 * 5**1 * 7**1 * 11**1 * 13**1 * 17**1 * 19**1
      #=> 232792560
    

    Ruby 有另一个方法,Prime::Prime.int_from_prime_division,它根据prime_division 返回的数组形式生成这个数字:

    Prime.int_from_prime_division([[2,4], [3,2], [5,1], [7,1], [11,1], [13,1],
      [17,1], [19,1]])
      #=> 232792560
    

    我们可以将其包含在以下计算中。

    def smallest_divisible_by_2_to_n(n)
      Prime.int_from_prime_division(
        (2..n).each_with_object({}) do |n,h|
          Prime.prime_division(n).each { |p,e| h[p] = [h[p].to_i, e].max }
        end.to_a)
    end
    

    请注意,如果哈希 h 没有密钥 p,则 h[p] #=> nil。正是出于这个原因,我将h[p].to_i 写成nil.to_i #=> 0。见Nilclass#to_i。这种方法正好适用于这种情况。

    smallest_divisible_by_2_to_n(10)
      #=> 2520
    smallest_divisible_by_2_to_n(20)
      #=> 232792560
    smallest_divisible_by_2_to_n(30)
      #=> 2329089562800
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-17
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多