Skip to content

Files

Latest commit

Jul 21, 2019
39ec1b2 · Jul 21, 2019

History

History

GCD

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Jul 21, 2019
Jul 21, 2019
Oct 29, 2018

最大公约数算法(Greatest Common Divisor)

两个数字ab最大公约数(或最大公因数)是将ab整除都没有余数的最大正整数。

例如,gcd(39, 52) = 13,因为13除以39(39/13 = 3)以及52(52/13 = 4),而且没有比13更大的数字。

在某些时候你可能不得不在学校里了解这一点。:-)

找到两个数字的GCD的费力方法是先找出两个数字的因子,然后取其共同的最大数。 问题在于分解数字是非常困难的,特别是当它们变大时。 (从好的方面来说,这种困难也是保证您的在线支付安全的原因。)

有一种更聪明的方法来计算GCD:欧几里德的算法。 这个算法主要观点是,

gcd(a, b) = gcd(b, a % b)

其中a%ba除以b的余数。

以下是Swift中这个想法的实现:

func gcd(_ a: Int, _ b: Int) -> Int {
  let r = a % b
  if r != 0 {
    return gcd(b, r)
  } else {
    return b
  }
}

在 playground 上,试试一些例子:

gcd(52, 39)        // 13
gcd(228, 36)       // 12
gcd(51357, 3819)   // 57

让我们分步完成第三个例子:

gcd(51357, 3819)

根据欧几里德的规则,这相当于,

gcd(3819, 51357 % 3819) = gcd(3819, 1710)

因为51357 % 3819的余数是1710。 详细计算为51357 = (13 * 3819) + 1710,但我们只关心余数部分。

所以gcd(51357, 3819)gcd(3819, 1710)相同。 这很有用,因为我们可以继续简化:

gcd(3819, 1710) = gcd(1710, 3819 % 1710) = 
gcd(1710, 399)  = gcd(399, 1710 % 399)   = 
gcd(399, 114)   = gcd(114, 399 % 114)    = 
gcd(114, 57)    = gcd(57, 114 % 57)      = 
gcd(57, 0)

现在不能再进一步划分了。 114 / 57的余数为零,因为114 = 57 * 2。 这意味着我们找到了答案:

gcd(3819, 51357) = gcd(57, 0) = 57

因此,在欧几里德算法的每个步骤中,数字变得更小,并且在某个点上,当它们中的一个变为零时它结束。

顺便说一下,两个数字的GCD也可能为1.它们被认为是 互素(译注:也叫互质)。 当没有数字将它们整除时会发生这种情况,例如:

gcd(841, 299)     // 1

下面是欧几里德算法略微不同的一种实现。 与第一个版本不同,它不使用递归,而只使用基本的while循环。

func gcd(_ m: Int, _ n: Int) -> Int {
  var a = 0
  var b = max(m, n)
  var r = min(m, n)

  while r != 0 {
    a = b
    b = r
    r = a % b
  }
  return b
}

函数顶部的 max()min() 确保我们总是用较大的数字除以较小的数字。

最小公倍数

与GCD相关的想法是 最小公倍数 或叫做LCM。

两个数字ab的最小公倍数是两者的倍数中最小的正整数。 换句话说,LCM可以被ab整除。

例如:lcm(2, 3) = 6,因为6可以被2整除,也可以被3整除。

我们也可以使用欧几里德算法计算LCM:

              a * b
lcm(a, b) = ---------
            gcd(a, b)

代码:

func lcm(_ m: Int, _ n: Int) -> Int {
  return m / gcd(m, n) * n
}

在playground中测试:

lcm(10, 8)    // 40

您可能不需要在任何实际问题中使用GCD或LCM,但是使用这种古老的算法很酷。 它首先由欧几里德在公元前300年左右他的书籍元素中描述。 有传言说他在攻击他的Commodore 64时,发现了这个算法。

作者:Matthijs Hollemans
翻译:Andy Ron
校对:Andy Ron