【问题标题】:How does this method determine the greatest common divisor?这种方法如何确定最大公约数?
【发布时间】:2016-12-29 02:25:23
【问题描述】:

在数学中,两个或多个整数的最大公约数 (gcd),当其中至少一个不为零时,是除以无余数的最大正整数。比如8和12的GCD是4。Wikipedia

以下方法可以确定GCD:

def gcd(a, b)
  if a % b == 0
    b
  else
    gcd(b, a % b)
  end
end
p gcd(4, 12)
#=> 4

这个方法是如何工作的?

如果a % b == 0 那么b 是可以进入ab 的最大数字是有道理的。

但为什么要再次调用相同的方法,但要切换 args 并再次取模?

我并没有探究 else 部分背后的原因。

编辑:

添加一些puts 语句以使其更清晰:

def gcd(a, b)
  puts "Inside gcd, a: #{a}, b: #{b}, a \% b: #{a % b}"

  if a % b == 0
    puts "Inside if, a: #{a}, b: #{b}, a \% b: #{a % b}"
    b
  else
    puts "Inside else, a: #{a}, b: #{b}, a \% b: #{a % b}"
    gcd(b, a % b)
  end
end

p gcd(55, 105)

标准输出:

Inside gcd, a: 55, b: 105, a % b: 55
Inside else, a: 55, b: 105, a % b: 55
Inside gcd, a: 105, b: 55, a % b: 50
Inside else, a: 105, b: 55, a % b: 50
Inside gcd, a: 55, b: 50, a % b: 5
Inside else, a: 55, b: 50, a % b: 5
Inside gcd, a: 50, b: 5, a % b: 0
Inside if, a: 50, b: 5, a % b: 0
5

【问题讨论】:

  • 也许只需添加一些puts 语句来查看它的作用?有趣的是,Ruby 内置了12.gcd(4) 函数。
  • 我认为如果您只是在 55 和 105 上尝试一下,该方法会更清晰。

标签: ruby algorithm math


【解决方案1】:

这就是所谓的Euclidean Algorithm

为了了解为什么需要交换数字并进行另一个递归调用,您需要了解其背后的实际数学原理。检查此YouTube video 以了解欧几里得算法的工作原理。否则,我在下面写了我对算法的解释。


欧几里得算法的形式化解释

输入

  • 两个正整数,a 和 b。

输出

  • a 和 b 的最大公约数 gcd。

内部计算

  • 如果 a
  • a 除以 b 得到余数 r。如果 r = 0,则将 b 报告为 a 和 b 的 GCD。
  • 将 a 替换为 b 并将 b 替换为 r。返回上一步。

例如:

gcd(40,7)

40 = 7(5) + 5 
 7 = 5(1) + 2
 5 = 2(2) + 1 <-- your gcd
 2 = 1(2) + 0

但是,这意味着...

gcd(40,7) = gcd(7, gcd(40,7)) =
gcd(7, 5) = gcd(5, gcd(7, 5)) =
gcd(5, 2) = gcd(2, gcd(5, 2)) = 
gcd(2, 1) = 0

gcd(a,b) = 0,b 等于 1,所以我们返回 b

现在这是重要的部分!如果我们不交换数字,我们将无法执行必要的数学运算,并最终跟踪 b 的位置,这是我们的 gcd .


因此,本质上需要交换以保持因素正确。尝试在没有交换的情况下进行数学运算,您很快就会明白为什么它很重要;)

希望这会有所帮助!

【讨论】:

    【解决方案2】:

    关键的事实是,对于 b 的每个除数 g,当且仅当 g 除以 a % b 时,我们有 g 除以 a(特别是,这适用于 GCD)。这是由恒等式 a = (a / b) * b + a % b,其中 / 是整数除法,因为 g 除以 a(分别为 a % b),而 g 除以 b 的所有倍数,包括 (a / b ) * b,因此 g 除以 a % b(分别为 a)。因此,如果递归调用终止,它会给出正确的结果,并且它终止是因为我们总是减小输入的大小(根调用除外)。

    切换参数的原因是较大的数字是第一个参数,因为 0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多