有一个快速的解决方案于此,只要该范围是1到N.
关键的观察是,如果n
(< N)有因式分解p_1^a_1 * p_2^a_2 * ... p_k * a_k
, 那么它将作为p_1^a_1
和p_2^a_2
,... p_k^a_k
贡献一模一样的因素对LCM。而且这些权力中的每一个也都在1到N范围内。因此,我们只需要考虑最高的纯黄金的权力小于N.
例如,对于20,我们有
2^4 = 16 < 20
3^2 = 9 < 20
5^1 = 5 < 20
7
11
13
17
19
乘以所有这些主要大国一起,我们得到所需的结果
2*2*2*2*3*3*5*7*11*13*17*19 = 232792560
所以在伪代码:
def lcm_upto(N):
total = 1;
foreach p in primes_less_than(N):
x=1;
while x*p <= N:
x=x*p;
total = total * x
return total
现在你可以调整内部环路窝rk略有不同,以获得更多速度,并且您可以预先计算primes_less_than(N)
函数。
编辑:
由于最近给予好评我decideded重温这一点,看到与其他上市算法的速度对比如何。是
时序范围1-160用10k迭代,对乔Beibers和马克赎金方法如下:
乔斯:1.85s 商标:3.26s 矿:0.33s
这里有一个日志-log图的结果达300
代码为我的测试可以在这里找到:
import timeit
def RangeLCM2(last):
factors = range(last+1)
result = 1
for n in range(last+1):
if factors[n] > 1:
result *= factors[n]
for j in range(2*n, last+1, n):
factors[j] /= factors[n]
return result
def lcm(a,b):
gcd, tmp = a,b
while tmp != 0:
gcd,tmp = tmp, gcd % tmp
return a*b/gcd
def EuclidLCM(last):
return reduce(lcm,range(1,last+1))
primes = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
947, 953, 967, 971, 977, 983, 991, 997 ]
def FastRangeLCM(last):
total = 1
for p in primes:
if p>last:
break
x = 1
while x*p <= last:
x = x * p
total = total * x
return total
print RangeLCM2(20)
print EculidLCM(20)
print FastRangeLCM(20)
print timeit.Timer('RangeLCM2(20)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(20)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(20)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(40)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(40)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(40)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(60)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(60)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(60)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(80)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(80)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(80)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(100)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(100)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(100)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(120)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(120)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(120)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(140)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(140)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(140)', "from __main__ import FastRangeLCM").timeit(number=10000)
print timeit.Timer('RangeLCM2(160)', "from __main__ import RangeLCM2").timeit(number=10000)
print timeit.Timer('EuclidLCM(160)', "from __main__ import EuclidLCM").timeit(number=10000)
print timeit.Timer('FastRangeLCM(160)', "from __main__ import FastRangeLCM").timeit(number=10000)
顺便说一句 - 就是答案10581480?我相信这是对特定问题:) – warren 2009-02-12 19:12:03
@warren正确的答案 - 我被你的答案吓坏了,因为一会儿我还以为你是对的(只是刚刚发现了这个问题),以及LCM计算器我在写哈斯克尔给出了一个截然不同的答案,10581480似乎可以被[1..20]整除。我一定是搞错了地方作为你的答案是不是11或16整除的正确答案是232792560. – 2010-01-28 10:17:56
@马特埃伦 - 良好的通话,我不知道如何在我的答案:) – warren 2010-01-28 14:27:33