CC++ & Algorithm

Python最小公倍数(LCM)

困难2
语言版本:C++Python
概述:最小公倍数是两个数共同的倍数中最小的那个,就像两个人下次同时过生日要等多少年。

最小公倍数(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. 相关知识点

学会了最小公倍数,你就能轻松解决“下次一起”的问题——无论是小伙伴的图书馆之旅,还是班级活动的时间安排,都不在话下!

例题精讲

1单选题

在Python中,要计算12和18的最小公倍数,以下哪个函数调用是正确的?

Amath.lcm(12,18)
Bmath.gcd(12,18)
Cmath.lcm([12,18])
Dmath.lcm(12,18,0)
2判断题

对于任意两个正整数a和b,有a * b = gcd(a,b) * lcm(a,b)。

3填空题
补全函数,使用数学方法计算两个正整数a和b的最小公倍数。

def lcm(a, b):
    import math
    return ___
4单选题

求三个数6, 10, 15的最小公倍数,以下哪个是正确的?

A30
B60
C90
D120
5判断题

使用while循环从较大的数开始递增检查是否能被两数整除的方法,比使用数学公式(a*b//gcd)更高效。