最小公倍数的概念与求法
困难4最小公倍数:从生活中的同时亮灯说起
你有没有遇到过这样的情况:你和朋友分别玩不同的游戏,每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),编程时注意先除后乘防溢出。掌握它,你就能轻松解决“下次同时发生”或“正好分完”的数学问题了!
例题精讲
两个互质的正整数的最小公倍数是多少?
两个数的最大公约数乘以它们的最小公倍数等于这两个数的乘积。
以下函数用于计算两个正整数a和b的最小公倍数。请补全代码。
function lcm(a, b) {
function gcd(x, y) {
if (y === 0) return x;
return gcd(y, x % y);
}
return a * b / ___;
}下列哪个数不是6和8的公倍数?
如果a是b的倍数,那么a和b的最小公倍数就是a。