python学习笔记8——数学中的约数问题
问题
问题1:最大公约数
给你两个正整数a和b, 输出它们的最大公约数
问题2:最小公倍数
给你两个正整数a和b, 输出它们的最小公倍数
问题3: 求解100以内的所有素数
输出100以内的所有素数,素数之间以一个空格区分
问题4: 公约数的个数
给你两个正整数a,b, 输出它们公约数的个数。
问题5: 逆解最大公约数与最小公倍数
我们经常遇到的问题是给你两个数,要你求最大公约数和最小公倍数。
今天我们反其道而行之,给你两个数a和b,计算出它们分别是哪两个数的最大公约数和最小公倍数。
输出这两个数,小的在前,大的在后,以空格隔开。若有多组解,输出它们之和最小的那组。
注:所给数据都有解,不用考虑无解的情况。
最大公约数的解法
辗转相除法
算法步骤
def gcd(b,a):
b,a=a,b%a
if a==0:
return b
else:
return gcd(b,a)
即就是取如果b与a不能整除,就取a和b除以a的余数再考察是个递归的思路。
1.举个栗子
一张长方形纸,长2703厘米,宽1113厘米.要把它截成若干个同样大小的正方形,纸张不能有剩余且正方形的边长要尽可能大.问:这样的正方形的边长是多少厘米?
解答:
可知:在长2703厘米、宽1113厘米的长方形纸的一端,依次裁去以宽(1113厘米)为边长的正方形2个。在裁后剩下的长1113厘米,宽477厘米的长方形中,再裁去以宽(477厘米)为边长的正方形2个。然后又在裁剩下的长方形(长477厘米,宽159厘米)中,以159厘米为边长裁正方形,恰好裁成3个,且无剩余。因此可知,159厘米是477厘米、1113厘米和2703厘米的约数。所以裁成同样大的,且边长尽可能长的正方形的边长应是159厘米。所以,159厘米是2703和1113的最大公约数。
让我们把过程转化为计算过程,即:
2703÷1113,商2余477;
1113÷477,商2余159;
477÷159,商3余0。
当余数为0时,最后一个算式中的除数159就是原来两个数2703和1113的最大公约数。
可见,477=159×3,
1113=159×3×2+159=159×7,
2703=159×7×2+477=159×7×2+159×3=159×17。
又∵7和17是互质数,
∴159是2703和1113的最大公约数。
我们把这种求最大公约数的方法叫做辗转相除法.辗转相除法的优点在于它能在较短的时间内求出任意两个数的最大公约数。
2.公式理解法
b=ak+r;如果一个数能整除a和r,那么一定能整除b
循环法
这里我们使用循环来代替前面的递归
while(b%a!=0):
a,b=b%a,a
print(a)
这样就简洁多了,并且时间复杂度是一样的,而且这个里面交换值的过程跟上面折纸的过程很像;
列表法
只有一行代码,使用max()函数;我认为是比较简洁的,但是效率很低。时间复杂度高。但是在一些比时间复杂度不是很高的场景里面可以快速把代码写出来。这里用的是求素数时的想法
print(max([i for i in range(1,b+1) if b%i==0 and a%i==0]))
解决方法
问题一: 最大公约数
def gca(a,b):
while(b%a!=0):
a,b=b%a,a
return a
print(gca(a,b))# 或者print(gca(b,a))#跟参数大小顺序无法
或者比较简单的方式
print(max([i for i in range(1,b+1) if b%i==0 and a%i==0]))
问题2:最小公倍数
假设a与b的最大公约数为k,即a=mk,b=nk;
则a,b的最小公倍数为m*n*k,也就是a*b/k = m*k*n*k/k = m*n*k
def gca(a,b):
while(b%a!=0):
a,b=b%a,a
return a
print(a*b/gca(a,b))
或者比较简单的方式
print(a*b/max([i for i in range(1,b+1) if b%i==0 and a%i==0]))
问题3: 求解100以内的所有素数
判断是不是素数就看它有没有除了1和它本身的约数
def isSushu(a):
if a<4:
return 0
for i in range(2,a-1):
if a%i==0:
return 1
return 0
print ' '.join([str(i) for i in range(2, 101) if not isSushu(i)])
下面是简洁的方法
from math import sqrt
print ' '.join([str(i) for i in range(2, 101) if 0 not in [ i%j for j in range(2,int(sqrt(i))+1)]])
问题4: 公约数的个数
print len([i for i in xrange(1,b+1) if b%i==0 and a%i==0])
问题5: 逆解最大公约数与最小公倍数
参考资料
range与xrange的区别
这两个输出的结果都是一样的,实际上有很多不同,range会直接生成一个list对象:
而xrange则不会直接生成一个list,而是每次调用返回其中的一个值【xrange返回的是一个生成器】。