繁体   English   中英

获得可被 1 到 n 整除的最小数的最快和最紧凑的方法

[英]Fastest and most compact way to get the smallest number that is divisible by numbers from 1 to n

我试图找到可被从 1 到 n 的数字整除的最小数字,现在我正在寻找有关如何进一步压缩/使我的解决方案更有效的建议。 如果也有 O(1) 的解决方案,那就太酷了。

def get_smallest_number(n):
    """
    returns the smallest number that is divisible by numbers from 1 to n
    """
    divisors = range(1, n+1)
    check_divisible = lambda x: all([x % y == 0 for y in divisors])
    i = 1
    while True:
        if check_divisible(i):
            return i
        i += 1

从数学上讲,您正在计算1, 2, ..., n的最小公倍数。 lcm很容易从gcd派生出来,并且lcm是一个关联操作。 reduce可用于将关联操作应用于可交互对象。 我们可以结合这些想法(以及评论中 Mark Dickinson 和 Eric Postpischil 的改进)来获得一个非常快速的解决方案:

from math import gcd
from functools import reduce

def lcm(a,b):
    return a // gcd(a,b) * b

def get_smallest_number2(n):
    return reduce(lcm,range(1 + n//2,n+1),1)

IPython 中的一些快速%timeit结果:

%timeit get_smallest_number2(15)
2.07 µs ± 26.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit get_smallest_number(15)
443 ms ± 5.75 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

对于n = 15 ,它因此快 200,000 倍以上。 您的 function 早在n = 100之前就无法产生任何 output ,但get_smallest_number2(100)几乎立即计算为69720375229712477164533808935312303556800

首先考虑阶乘 n。这显然可以被所有小于 n 的数整除。 但不是这样的最小数字,例如,您可以将 n 除以 6。较小的结果仍可被 2 和 3 整除,因此仍可被 6 整除。

我们可以划分出哪些数字? 只要存在所有必需的素数,复合材料(如 6)就无关紧要:在这种情况下为 2 和 3。 素数免费为您提供复合材料。 所以,专注于素数。

从 2 开始。查看 2 的幂:2、4、8、16、... 遍历 2 的幂,直到找到小于或等于 n 的最高幂。 这是您需要的唯一 2 的幂,所有较低的幂都是不必要的。 如果 n 为 8 或更高,则不需要明确包含 4,因为这样您将拥有 8、16 或其他任何乘数。 重复 3 的幂:3, 9, 27, 81, ... 直到 sqrt(n) 的素数。 超过这一点,您只需要小于 n 的剩余素数,因为这些素数的更高幂将超过 n。

将选定的素数乘以得到最小的 n。

使用埃拉托色尼筛法生成初始素数列表,最多为 n。

实现 LCM 的另一种方法

import time
from datetime import timedelta


start_time = time.monotonic()
 

def lcm(nums):
    res = 1
    for i in nums:
        res = (res * i) // gcd(res, i)
    return res
    
def gcd(a, b):
    while b:
        a, b = b, a%b
    return a
    
print(lcm([8, 9, 10, 11, 12, 13, 14, 15]))




end_time = time.monotonic()
print(f'Duration: {timedelta(seconds=end_time - start_time)}')

生产

360360
Duration: 0:00:00.000061

[Program finished]

这个想法是在每次迭代中添加最高分频器并从高到低检查。 像这样的东西:

n = int(input("n = "))
result = 0
while True:
    result += n
    for i in range(n, 1, -1):
        if result % i != 0:
            break
    else:
        break
print(result)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM