CC++ & Algorithm

最小公倍数的概念与求法

困难4
语言版本:通用
概述:最小公倍数是几个数公有的倍数中最小的那个,通过同时亮灯、遇到同一个时间点等例子引入,并给出与GCD的关系及代码实现。

最小公倍数:从生活中的同时亮灯说起

你有没有遇到过这样的情况:你和朋友分别玩不同的游戏,每5分钟休息一次,每8分钟休息一次,你们想同时休息,那要等多久?或者,你每天攒3元零花钱,朋友每天攒4元,你们想在同一天攒到整块钱去购物,最少要几天?这些问题里,其实都藏着一个数学概念——最小公倍数

最小公倍数(Least Common Multiple,简称LCM)就是几个数公有的倍数中最小的那个正数。它帮我们找到“下次一起发生”的时刻,或者“正好分完”的最小数量。


1. 先弄明白:什么是倍数?什么是公倍数?

倍数:一个数乘以1、2、3……得到的数,就是这个数的倍数。比如:

  • 3的倍数:3, 6, 9, 12, 15, 18, …
  • 4的倍数:4, 8, 12, 16, 20, …

公倍数:两个或多个数共同的倍数。比如3和4的公倍数有:12, 24, 36, … 其中最小的12就是它们的最小公倍数。

生活中的例子

  • 红绿灯同时亮:红灯每12秒亮一次,绿灯每18秒亮一次。它们下一次同时亮的时间就是12和18的最小公倍数。12的倍数:12, 24, 36, 48, …;18的倍数:18, 36, 54, …;共同出现的最小的是36,所以36秒后它们会再次同时亮起。
  • 分组游戏:班级同学分组,如果每组4人刚好分完,每组6人也刚好分完,那么班级最少人数就是4和6的公倍数,最小是12人。
  • 买零食:小明每3天买一次薯片,小红每5天买一次巧克力。他们今天一起买了,那么下次一起买零食最少要等多少天?答案就是lcm(3,5)=15天。

2. 最小公倍数怎么求?

方法一:列举法(适合小数)

就是像上面那样,把每个数的倍数写出来,找出最小的公共数。比如求lcm(8, 12):

  • 8的倍数:8, 16, 24, 32, 40, …
  • 12的倍数:12, 24, 36, 48, … 最小公倍数是24。

方法二:质因数分解法(适合讲解原理)

把每个数分解成质因数相乘,然后取每个质因数的最高次幂相乘。

例如:12 = 2² × 3,18 = 2 × 3²。
最高次幂:2²(因为2的指数2比1大),3² → 2²×3² = 4×9 = 36。

方法三:利用最大公约数(GCD)公式(最常用)

重要公式

lcm(a, b) = a × b ÷ gcd(a, b)

其中gcd(a, b)是a和b的最大公约数。

为什么成立?因为a和b的乘积包含了它们所有质因数的指数之和,而最大公约数包含了公共质因数的最小指数,相除后正好得到每个质因数的最大指数。
例如:a=12,b=18,gcd=6,a×b=216,216÷6=36,正是lcm。

用这个公式计算特别快,尤其是数字很大时,不需要列出所有倍数。


3. 多个数的最小公倍数怎么求?

可以两两递归:
lcm(a, b, c) = lcm(lcm(a, b), c)

例如:求4、6、8的最小公倍数。
先算lcm(4,6)=12,再算lcm(12,8)=24,所以lcm(4,6,8)=24。

验证:24是4的倍数(24÷4=6)、6的倍数(24÷6=4)、8的倍数(24÷8=3),且比24小的正数(比如12)不是8的倍数,所以24最小。


4. 新手容易犯的错误

  • ❌ 误以为公倍数就是最小公倍数:公倍数有很多,比如36也是12和18的公倍数,但最小的是36吗?不对,12和18的最小公倍数是36?等等,前面我们算的是36吗?再检查一下:12的倍数:12,24,36…;18的倍数:18,36…;公倍数有36,72…,最小确实是36。但注意,有时最小公倍数可能比其中一个数小吗?不会,至少等于较大的那个数?不一定,比如lcm(2,3)=6,比3大;但lcm(4,6)=12比6大。最小公倍数一定不小于每个数本身。
  • ❌ 计算时先乘后除导致溢出:如果a和b很大(比如10亿),a*b可能超过int范围。正确做法:先除以gcd再乘,即 a / gcd(a,b) * b
  • ❌ 忘记考虑正整数:最小公倍数通常针对正整数。如果输入0或负数,定义不同,一般不会在应用题中出现。
  • ❌ 求多个数时顺序不对:一定要两两递归,不能用乘积除以所有数的gcd(那是不同概念)。例如求lcm(4,6,8),不能直接用4*6*8 / gcd(4,6,8),因为gcd(4,6,8)=2,乘积192÷2=96,但正确答案是24,差远了。

5. 完整代码示例

C++ 实现(附中文注释)

#include <iostream>
using namespace std;

// 求最大公约数(辗转相除法)
int gcd(int a, int b) {
    while (b != 0) {
        int temp = a % b;  // 余数
        a = b;
        b = temp;
    }
    return a;
}

// 求两个数的最小公倍数
int lcm(int a, int b) {
    // 先除以gcd再乘,防止溢出
    return a / gcd(a, b) * b;
}

// 求多个数的最小公倍数(数组形式)
int lcm_multi(int arr[], int n) {
    int result = arr[0];          // 从第一个数开始
    for (int i = 1; i < n; i++) {
        result = lcm(result, arr[i]);  // 两两计算
    }
    return result;
}

int main() {
    // 测试两个数
    int a = 12, b = 18;
    cout << "lcm(" << a << "," << b << ") = " << lcm(a, b) << endl;  // 输出36

    // 测试三个数:4, 6, 8
    int nums[] = {4, 6, 8};
    int n = sizeof(nums) / sizeof(nums[0]);
    cout << "lcm(4,6,8) = " << lcm_multi(nums, n) << endl;  // 输出24

    // 验证公式 a*b/gcd
    cout << "a * b / gcd = " << a * b / gcd(a, b) << endl;  // 也输出36

    return 0;
}

Python 实现(附中文注释)

def gcd(a, b):
    """辗转相除法求最大公约数"""
    while b:
        a, b = b, a % b
    return a

def lcm(a, b):
    """求两个数的最小公倍数"""
    return a // gcd(a, b) * b   # // 是整数除法

def lcm_multi(numbers):
    """求列表里所有数的最小公倍数"""
    result = numbers[0]                       # 从第一个数开始
    for num in numbers[1:]:                   # 遍历剩余的数
        result = lcm(result, num)             # 两两计算
    return result

# 测试两个数
a, b = 12, 18
print(f"lcm({a},{b}) = {lcm(a, b)}")          # 输出36

# 测试三个数
nums = [4, 6, 8]
print(f"lcm(4,6,8) = {lcm_multi(nums)}")      # 输出24

# 验证公式
print(f"a * b // gcd = {a * b // gcd(a, b)}") # 也输出36

6. 相关知识点指引

  • 最大公约数(GCD):最小公倍数的好搭档,通过辗转相除法可以快速求得。想了解GCD的原理,可以看本系列另一篇文章《最大公约数与欧几里得算法》。
  • 质因数分解:如果想从原理上理解LCM和GCD的关系,需要掌握如何把数分解成质因数。
  • 分数通分:分数的加减运算需要找到分母的最小公倍数作为公分母,这就是LCM在分数中的应用。
  • 周期问题:很多应用题(如“再过多少天同时发生”)都可以转化为求LCM的问题。

总结:最小公倍数就是几个数共有的倍数中最小的那个。它和最大公约数有简单公式 lcm(a,b) = a×b÷gcd(a,b),编程时注意先除后乘防溢出。掌握它,你就能轻松解决“下次同时发生”或“正好分完”的数学问题了!

例题精讲

1单选题

两个互质的正整数的最小公倍数是多少?

A它们的和
B它们的积
C它们的差
D它们的最大公约数
2判断题

两个数的最大公约数乘以它们的最小公倍数等于这两个数的乘积。

3填空题
以下函数用于计算两个正整数a和b的最小公倍数。请补全代码。

function lcm(a, b) {
    function gcd(x, y) {
        if (y === 0) return x;
        return gcd(y, x % y);
    }
    return a * b / ___;
}
4单选题

下列哪个数不是6和8的公倍数?

A24
B48
C72
D36
5判断题

如果a是b的倍数,那么a和b的最小公倍数就是a。