Smallest multiple 求1-20的最小公倍数

'''
题目出处
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

求最小的某个数的因子包含连续自然数1-20
'''
分析:

从1开始依次递增,直到这个数能被1-20整除。那么这个数是符合条件的。

因为它能被1-20整除,那么肯定也能被1-10整除,所以起始位置可以是2520.

因为需要被1-20整除,那么肯定也能被11, 13, 17, 19整除,那么递增的步长: step = 11*13*17*19

然后得到条例条件的数。此时的起始值是2520 * step

step = 11 * 13 * 17 * 19
start  = 2520 * step
target = start
while True:
	if target % 12 == 0 and target % 14 == 0 and target % 15 == 0 and \
		target % 16 == 0 and target % 18 == 0 and target % 10 == 0:
		break
	else:
		target += step

print target
因为target已经是1-10及11,13,17,19的倍数了,所以在计算的过程中不需要再次计算


这里其实也是求1-20的最小公倍数,求最小公倍数有通用的算法,可以自行查找。

这里用python实现最小公倍数lcm(fir, sec)

def lcm(fir, sec):
	mutil = fir * sec
	while fir % sec != 0:
		fir, sec = sec, fir % sec
	return mutil / sec
然后用下面这个语句即可求得1-20的最小公倍数

print reduce(lcm, [i for i in xrange(1, 21)])
函数reduce:reduce(func, seq[,init])  

将函数func作用于序列seq,每次取seq中前2个值,计算得到的结果返回到seq中,

继续取值计算,

直到序列中只剩下一个元素,返回该元素

对于采用最小公倍数实现计算,还可以改进,在此不做分析。

这里对于最小公倍数的处理还不好。一般来说,最小公倍数会和最大公约数一起。

这里重新实现:

def lcm(fir, sec):
	return fir * sec / gcd(fir, sec)

def gcd(fir, sec):
	while fir % sec != 0:
		fir, sec = sec, fir % sec
	return sec
这样看起来更清晰

对于计算多个数的最小公倍数,一是可以两丙取其最小公倍数,然后合并

二是,取所有数的素因子分解中出现的所有最大的素因子,然后相乘得到最小公倍数

4 = 2 ^2 6 = 2 * 38 = 2^39 = 3^2 10 = 2*5

12 = 3*4 14 = 2*715 = 3*516 = 2^418 = 2*9

20 = 4*5

在这些分解中,素因子分别为:19, 17, 13, 11, 7, 5, 3^2, 2^4

由这些数相乘后,得到结果,即为题目所求。

对于这个算法,可以先求得所有素数,然后对20(这里是20)对素因子取对数并取整,得到素因子的最大指数

然后把这些素数及因子相乘,得到结果。

def isprime(n):
	if n < 2: return False
	for i in xrange(2, int(math.sqrt(n)) + 1):
		if n % i == 0:
			return False
	return True

def smallest_multiple(target):
	if target < 1: return None
	if target < 2: return target
	res = 1
	for num in xrange(2, target + 1):
		if isprime(num):
			power = int(math.floor(math.log(target, num)))
			res *= (num ** power)
	return res
在这里,遍历target以下所有的数,判断是否是素数,若是,那么求得它的最大幂指数,然后与之前得到的结果相乘

最后返回计算的结果

这里在判断素数的时候,重复比较多,可以用另外一种方式来写:

def smallest_multiple(target):
	if target < 1: return None
	if target < 2: return target
	res = 1
	numlist = [1] * (target + 1)
	numlist[0:1] = [0, 0]
	for i in xrange(2, target + 1):
		if numlist[i] == 1:
			numlist[i+i::i] = [0] * ((target + 1 - i) / i)
			power = int(math.floor(math.log(target, i)))
			res *= (i ** power)
	return res
在计算素数的过程 ,把后面的非素数(当前素数的倍数)去掉一部分,这样计算量会小一些。

若是对于numlist[i+i :: i] = [0] * ((target + 1 - i) / i) 这一步的长度有不理解的,

可以用numlist[i+i :: i] = [0] * len(numlist[i+i :: i]) 这个来替换


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值