GCD 与 LCM

GCD与LCM

本文将系统讲解两个核心概念——最大公约数(GCD)最小公倍数(LCM),包括定义、性质、数学证明、编程实现及应用场景。

最大公约数(GCD)

GCD定义

整数a和b的最大公约数(Greatest Common Divisor,简称GCD),是指能同时整除a和b的所有正整数中最大的那个,记为gcd(a, b)。

  • 示例:gcd(15, 81) = 3(3是能同时整除15和81的最大整数)。
  • 注意:由于正负数的因子完全相同(如-15的因子与15一致),因此gcd(a, b) = gcd(|a|, |b|)。编程时只需处理正整数,简化逻辑。

GCD核心性质

GCD具有多个重要性质,是推导算法和解决问题的基础:

  1. 辗转性:gcd(a, b) = gcd(a, a + b) = gcd(a, k * a + b)(k为任意整数)。
    • 例:gcd(5, 3) = gcd(5, 5 + 3) = gcd(5, 8) = 1。
  2. 数乘性:gcd(k * a, k * b) = k * gcd(a, b)(k为正整数)。
    • 例:gcd(2 * 3, 2 * 5) = 2 * gcd(3, 5) = 2 * 1 = 2。
  3. 多变量扩展性:多个整数的 GCD 可通过两两计算推导,即gcd(a, b, c) = gcd[gcd(a, b), c]。
    • 例:gcd(4, 6, 8) = gcd[gcd(4,6), 8] = gcd(2, 8) = 2。
  4. 互素性:若gcd(a, b) = d,则gcd(a / d, b / d) = 1(即a / d与b / d互素,没有除1外的公约数)。
    • 例:gcd(12, 18) = 6,则gcd(12 / 6, 18 / 6) = gcd(2, 3) = 1。
  5. 消去性:gcd(a + c * b, b) = gcd(a, b)(c为任意整数)。
    • 例:gcd(5 + 2 * 3, 3) = gcd(11, 3) = 1,与gcd(5, 3) = 1一致。

GCD编程实现:欧几里得算法

欧几里得算法(又称辗转相除法)是计算 GCD 的高效算法,核心公式为:
gcd(a, b) = gcd(b, a % b)()

  • 边界条件:若b = 0,则gcd(a, 0) = a。
  • 适用范围:a ≥ 0,b > 0,若b等于0,则结果为0(若 a < b,第一次递归会自动交换位置,如gcd(3, 5) = gcd(5, 3 % 5) = gcd(5, 3)。

证明

欧几里得算法的正确性可通过以下两步证明:

证明1:(a, b)与(b, a % b)的公约数完全相同

设a = k * b + r(其中r = a % b,满足0 ≤ r < b):

  1. 若d是a和b的公约数,则r = a - k * b可被d整除(因a和k * b均能被d整除),故d也是b和r的公约数。
  2. 若d是b和r的公约数,则a = k * b + r可被d整除(因k * b和r均能被d整除),故d也是a和b的公约数。

因此,(a, b)与(b, a % b)的公约数集合完全一致,最大公约数也必然相等。

证明2:基于素数分解的验证

设c = gcd(a, b),则可将a和b表示为:
a = m * c,b = n * c(其中m和n为互素的正整数,即gcd(m, n) = 1)。

由r = a % b可知r = a - q * b(q为商,正整数),代入a和b的表达式:
r = m * c - q * n * c = (m - q * n) * c

此时b = n * c,r = (m - q * n) * c,且n与(m - q * n)互素(反证法:若n与(m - q * n)有公约数 ,则n = x * d,m - q * n = y * d其中x,y,d都是正整数,且d > 1,则 a = m * c = (q * x + y) * d * c,b = x * d * c,这时a,b的最大公约数变成d * c,与前提矛盾,所以n,m - q * n一定互质)。

因此gcd(b, r) = c = gcd(a, b),即gcd(a, b) = gcd(b, a % b)。

代码实现

  • java
    /**
     * 欧几里得算法计算最大公约数(GCD)
     * @param a 整数a(非负)
     * @param b 整数b(非负,且不与a同时为0)
     * @return a和b的最大公约数
     */
    int gcd(int a, int b) {
        // 边界条件:若b为0,返回a(a此时非负)
        if (b == 0) {
            return a;
        }
        // 递归调用:gcd(a,b) = gcd(b, a%b)
        return gcd(b, a % b);
    }
    
  • C++
    int gcd(int a, int b) {
        if (b == 0) {
          return a;
        }
        return gcd(b, a % b);
    }
    

最小公倍数(LCM)

LCM定义

整数a和b的最小公倍数(Least Common Multiple,简称LCM),是指能同时被a和b整除的所有正整数中最小的那个,记为lcm(a, b)。

  • 示例:lcm(5, 6) = 30(30是能同时整除5和6的最小整数)。
  • 注意:若a或b为0,LCM 无意义,编程时需确保输入为非零整数。

LCM与GCD的关系:基于算数基本定理

算数基本定理

任何大于1的正整数n,都可唯一分解为有限个素数的乘积(素数因子从小到大排列):
latex-1762220844819
其中p_i为素数且从小到大,C_i为正整数(素数的指数)。

GCD与LCM的素数分解表达式

设整数a和b的素数分解为:
latex-1762220941338
(若某素数仅在一个数中出现,另一数的对应指数取0,如a = 2 ^ 3,b = 3 ^ 2,则a = (2 ^ 3) * (3 ^ 0)),b = (2 ^ 0) * (3 ^ 2))。

则:

  • GCD取各素数的最小指数latex-1762221053733
  • LCM取各素数的最大指数latex-1762221062772

核心公式:lcm(a, b) = (a * b) / gcd(a, b)

由素数分解表达式可推导:
latex-1762221122592

由于min(x, y) + max(x, y) = x + y,因此:
gcd(a, b) * lcm(a, b) = a * b

整理得 LCM 计算公式:
lcm(a, b) = (a * b) / gcd(a, b)

关键优化:计算时需先做除法再做乘法(即a / gcd(a, b) * b ),避免a * b超出整数范围导致溢出(如a = 10 ^ 9,b = 10 ^ 9,a * b = 10 ^ 18,超出int范围,但 a / gcd(a, b) * b = 1 * 10 ^ 9 = 10 ^ 9无溢出)。

LCM编程实现

基于GCD函数,直接套用核心公式即可实现LCM,需注意处理输入不为0的情况。

代码实现

  • java
    /**
     * 计算最小公倍数(LCM):基于GCD公式
     * @param a 正整数a
     * @param b 正整数b
     * @return a和b的最小公倍数
     */
    int lcm(int a, int b) {
        // 处理输入为0的情况
        if (a == 0 || b == 0) {
            return -1;
        }
        return a / gcd(a, b) * b;
    }
    
    // 复用之前实现的GCD函数
    int gcd(int a, int b) {
        if (b == 0) {
            return a;
        }
        return gcd(b, a % b);
    }
    
  • C++
    int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
    int lcm(int a, int b) {
        return (a == 0 || b == 0) ? -1 : a / gcd(a, b) * b;
    }
    

总结

概念 核心公式/定理 编程实现核心 典型应用场景
GCD gcd(a, b) = gcd(b, a % b) 欧几里得算法(递归/迭代) 约分、LCM计算、裴蜀定理前置
LCM lcm(a, b) = (a * b) / gcd(a,b) 基于GCD推导 分数通分、周期计算(如两个事件同时发生的时间)
posted @ 2025-11-04 10:02  Jing61  阅读(82)  评论(0)    收藏  举报