Python最小公倍数(LCM)
困难2最小公倍数(LCM)——帮我们找“下次一起”的日子
你有没有遇到过这种情况:小明每3天去一次图书馆,小红每4天去一次。今天他们在图书馆碰巧遇见了,那么下一次再相遇要等多少天?答案是12天,因为3和4的共同倍数中最小的那个是12。这个“最小的共同倍数”就叫做最小公倍数(Least Common Multiple,简称LCM)。生活中像这样找“下次一起”的时刻特别多,比如两个人跑步圈数、两路公交车到站时间、零食包装组合……掌握最小公倍数,就能轻松搞定这些周期问题。
1. 什么是“公倍数”和“最小公倍数”
- 倍数:一个数乘以1、2、3……得到的结果。比如3的倍数有3、6、9、12、15……
- 公倍数:两个数共同的倍数。比如3和4的公倍数有12、24、36……
- 最小公倍数:公倍数里最小的那个。3和4的最小公倍数就是12。
生活中的例子
- 妈妈每2天浇一次花,爸爸每3天浇一次。今天他们一起浇了,下次一起浇要过多少天?2和3的最小公倍数是6,所以6天后。
- 小丽有零花钱,她每5天买一次零食,小红每7天买一次。今天她俩都买了,下次一起买要过35天(5×7,因为它们互质)。
2. 怎么求最小公倍数?最常用的方法:利用最大公约数
Python里最快的方法是用一个公式:
a和b的最小公倍数 = a × b ÷ a和b的最大公约数
写成代码就是:
import math
def lcm(a, b):
"""返回a和b的最小公倍数"""
return a * b // math.gcd(a, b) # 用整除 //,保证结果是整数
print(lcm(3, 4)) # 输出 12
print(lcm(6, 8)) # 输出 24
print(lcm(5, 7)) # 输出 35(两个素数,没有公共因子)
这里我们用 math.gcd(a, b) 求最大公约数(GCD),然后做乘法再整除。
为什么这个公式成立?
你可以把两个数像积木一样拆开:
- a 和 b 的乘积等于“它们的所有因子全部乘在一起”。
- 最大公约数就是他们共同拥有的那堆因子(比如6和8的最大公约数是2,表示它们都含有因子2)。
- 如果直接乘,公共因子就被乘了两次。除以最大公约数,就相当于只保留一份公共因子,这样得到的数既能被a整除又能被b整除,而且是最小的。
试试看:6和8
- 最大公约数 gcd(6,8)=2
- 6×8=48,48÷2=24
- 检查:24÷6=4,24÷8=3,没错。而且比24更小的公倍数(比如12)不能被8整除,所以24是最小的。
3. 暴力枚举法(理解用的,不推荐实际用)
如果想从零理解,也可以从1开始一个一个数往上查,直到这个数能同时被a和b整除。
def lcm_bruteforce(a, b):
"""暴力枚举法:从较大的数开始试"""
big = max(a, b)
while True:
if big % a == 0 and big % b == 0:
return big
big += 1
print(lcm_bruteforce(3, 4)) # 输出 12
但这种方法当数字很大时非常慢(比如999和1000),所以实际都用公式法。
4. 多个数的最小公倍数
有时我们需要找三个或更多数的共同周期。比如小明、小红、小刚分别每2、3、4天去一次图书馆,今天都去了,下次都去要多少天?
方法:先把前两个数的最小公倍数算出来,再用这个结果和第三个数算一次,重复下去。
import math
def lcm(a, b):
return a * b // math.gcd(a, b)
def lcm_list(nums):
"""求列表中所有数的最小公倍数"""
result = nums[0]
for i in range(1, len(nums)):
result = lcm(result, nums[i])
return result
print(lcm_list([2, 3, 4])) # 输出 12
print(lcm_list([4, 6, 8])) # 输出 24
生活例子:三种零食包装分别是每6包、10包、15包一箱,要凑齐整箱最少需要多少包?答案是30(6、10、15的最小公倍数)。
5. 新手容易犯的错误
❌ 错误1:用 / 而不是 //
a * b / math.gcd(a, b) 在Python3中会得到浮点数(比如12.0),可能影响后续运算。应该用整数除法 // 得到整数。
❌ 错误2:忘记 import math
直接写 math.gcd 会报错。记得在文件开头加上 import math。
❌ 错误3:没有考虑0的情况
如果a或b是0,数学上最小公倍数通常定义为0,但 math.gcd(0, x) 会返回x,公式 0 * x // x 得到0,没问题。但如果两个都是0,math.gcd(0,0) 会抛出异常。实际编程中可以先判断是否为0。
❌ 错误4:混淆最大公约数和最小公倍数
最大公约数是最大的公共约数,最小公倍数是最小的公共倍数。可以用一个简单的口诀记:“公约数求最大,公倍数求最小,乘除一下得结果”。
6. 完整可运行的示例
下面是一个完整程序,包含了求两个数和多个数的最小公倍数,并附带了生活例子:
import math
def lcm_two(a, b):
"""返回两个数的最小公倍数"""
# 如果有一个数是0,最小公倍数为0
if a == 0 or b == 0:
return 0
return a * b // math.gcd(a, b)
def lcm_many(nums):
"""返回列表nums中所有数的最小公倍数"""
result = nums[0]
for i in range(1, len(nums)):
result = lcm_two(result, nums[i])
return result
# 例子:小明每3天去图书馆,小红每4天,小刚每6天
day1 = 3 # 小明周期
day2 = 4 # 小红周期
day3 = 6 # 小刚周期
print("小明和小红下次相遇:", lcm_two(day1, day2), "天后") # 12
print("三人下次都相遇:", lcm_many([day1, day2, day3]), "天后") # 12(因为12也是6的倍数)
# 另一个例子:两种饮料包装,一种每8瓶一箱,一种每12瓶一箱
box1 = 8 # 第一种箱子容量
box2 = 12 # 第二种箱子容量
print("两种箱子容量相同的最小瓶数:", lcm_two(box1, box2)) # 24
运行结果:
小明和小红下次相遇: 12 天后
三人下次都相遇: 12 天后
两种箱子容量相同的最小瓶数: 24
7. 相关知识点
- 最大公约数(GCD):最小公倍数的好搭档,求LCM的核心工具。
- 整除与取余:判断一个数能否被另一个数整除,在暴力枚举法中用到。
- 循环与迭代:多个数求LCM时需要用到循环。
- 数学公式推导:理解为什么LCM = a*b/GCD,可以帮你更好地记忆。
学会了最小公倍数,你就能轻松解决“下次一起”的问题——无论是小伙伴的图书馆之旅,还是班级活动的时间安排,都不在话下!
例题精讲
在Python中,要计算12和18的最小公倍数,以下哪个函数调用是正确的?
对于任意两个正整数a和b,有a * b = gcd(a,b) * lcm(a,b)。
补全函数,使用数学方法计算两个正整数a和b的最小公倍数。
def lcm(a, b):
import math
return ___求三个数6, 10, 15的最小公倍数,以下哪个是正确的?
使用while循环从较大的数开始递增检查是否能被两数整除的方法,比使用数学公式(a*b//gcd)更高效。