最大公约数与最小公倍数的最快速求法
一. 前言
我们不需要记住那么多知识,我们需要的是会合理的调用知识。
不要当个硬盘,要当cpu。
如求最大公约数/最小公倍数方法各种各样,数不胜数,难道我们全部都要记住吗?
不需要,记住最优解就行啦,这里直接告诉大家答案:最大公约数用math.gcd函数;最小公倍数用两数之积除以最小公倍数。
二. 求解方法
import math # 最大公约数------------------------------------------------------------------------- def max_divisor1(a, b): """ 暴力枚举法:遍历小的数的一半值,如果能都将它们整除,那么就是该值。 """ big = max(a, b) small = min(a, b) if big % small == 0: return small for i in range(small // 2, 1, -1): if small % i == 0 and big % i == 0: return i return 1 def max_divisor2(a, b): """ 辗转相除法(欧几里得算法、递归算法):两个数本身相除,取余值和最小值再相除,直到整除 """ big = max(a, b) small = min(a, b) if big % small == 0: return small return max_divisor2(big % small, small) def max_divisor3(a, b): """ 更相减损法:两个正整数a和b(a>b),它们的最大公约数等于a-b的差值c和较小数b之间的最大公约数。(即:每次都是求差值和较小数之间最大公约数,直到两个数相等为止,最大公约数就是最终相等的这两个数的值。避免了取模运算,但是算法性能不稳定,最坏时间复杂度为O(max(a,b))。缺点:更相减损术是不稳定的算法,当两数相差悬殊时,如计算10000和1的最大公约数,就要递归9999次。运算次数太多, """ if a == b: return a big = max(a, b) small = min(a, b) return max_divisor3(big - small, small) def max_divisor4(a, b): """ 把辗转相除法和更相减损术结合起来,在更相减损术的基础上使用移位运算。(移位运算差不多是辗转相除法的运用,不过是遇到偶数时,每次向右移一位,对于整数十进制来说,相当于除以2)求最大公约数的方法简写为gcd. 当a、b均为偶数时,dvr(a,b)=2gcd(a/2,b/2)=2dvr(a>>1,b>>1)=dvr(a>>1,b>>1)<<1 当a为偶数b为奇数时,dvr(a,b)=dvr(a/2,b)=dvr(a>>1,b) 当a为奇数b为偶数时,dvr(a,b)=dvr(a,b/2)=dvr(a,b>>1) 当a、b均为奇数时,先利用更相减损术减一次,dvr(a,b)=dvr(a-b,b),此时a-b必为偶数,然后又可以继续进行移位运算。 移位运算的性能非常好。这种方法在两数都比较小时,看不出来计算的优势;当两数越大时,计算次数的减少就会越明显。这种方法既避免大整数取模,又减少了运算次数,而且算法性能稳定,时间复杂度为O(log(max(a,b))) 补充: & 与 两个位都为1时,结果才为1 | 或 两个位都为0时,结果才为0 ^ 异或 两个位相同为0,相异为1 ~ 取反 0变1,1变0 << 左移 各二进位全部左移若干位,高位丢弃,低位补0 >> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) """ if a == b: return a if (a & 1) == 0 and (b & 1) == 0: return max_divisor4(a >> 1, b >> 1) << 1 elif (a & 1) == 0 and (b & 1) != 0: return max_divisor4(a >> 1, b) elif (a & 1) != 0 and (b & 1) == 0: return max_divisor4(a, b >> 1) else: big = max(a, b) small = min(a, b) return max_divisor4(big - small, small) # 最小公倍数------------------------------------------------------------------------------ def min_multiple1(x, y): """ 找到最大值进行递增直到全部整除 """ greater = x if x > y else y while True: if (greater % x == 0) and (greater % y == 0): lcm = greater break greater += 1 return lcm # 最简操作 def max_divisor_min_multiple(x, y): """ 最大公约数:gcd方法 最小公倍数:两数之积整除最大公约数,math模块没必要再搞个方法 """ # return math.gcd(x, y) return (x * y) // math.gcd(x, y) if __name__ == '__main__': print(max_divisor_min_multiple(4, 8))