项目Euler在python中获得最小的倍数

时间:2013-10-13 18:01:37

标签: python algorithm

我在Project Euler中遇到问题5:“2520是可以除以1到10之间的每个数字的最小数字,没有任何余数。

从1到20的所有数字均可被整除的最小正数是多少?“

我构造了以下代码,当使用1 - 10作为除数时找到正确的值2520,但是当使用1 - 20时代码似乎永远存在。 我再次不希望代码只是一个指针或两个我错的地方。 感谢

def smallestDiv(n):
    end=False
    while end == False:
        divisors = [x for x in range(1,21)]    # get divisors
        allDivisions = zip(n % i for i in divisors)    # get values for  n % all integers in divisors
        check = all(item[0]  == 0 for item in allDivisions )   # check if all values of n % i are equal to zero
        if check:         # if all values are equal to zero return n
            end = True
            return n
        else:             # else increase n by 1
            n +=1

编辑:

我使用了一些我发现的与LCM有关的代码,并使用reduce来解决问题:

def lcm(*values):
    values = [value for value in values]
    if values:
        n  = max(values)
        m = n
        values.remove(n)
        while any( n % value for value in values ):
            n +=m
        return n
    return 0

print reduce(lcm, range(1,21))

8 个答案:

答案 0 :(得分:21)

如果问题很难,请尝试解决更简单的版本。这里,如何计算两个数字的最低公倍数。如果你已经读过任何数论理论书(或者考虑素数因子),你可以使用最大公约数函数(由欧几里德算法实现)来做到这一点。

from fractions import gcd
def lcm(a,b):
    "Calculate the lowest common multiple of two integers a and b"
    return a*b//gcd(a,b)

观察lcm(a,b,c) ≡ lcm(lcm(a,b),c)使用Python reduce函数解决问题很简单

>>> from functools import reduce
>>> reduce(lcm, range(1,10+1))
2520
>>> reduce(lcm, range(1,20+1))
232792560

答案 1 :(得分:4)

你正在进行强力搜索,所以它可以长任意。您应该阅读有关LCM(最少公倍数)的信息,以便编写有效的解决方案。(我认为是232792560

答案 2 :(得分:2)

int gcd(int m, int n)
{
    int t;
    while(n!=0)
    {
        t=n;
        n=m%n;
        m=t;
    }
    return m;
}

#include<stdio.h>
int main()
{
    int i,n;
    int long long lcm=1;
    printf("Enter the range:");
    scanf("%d",&n);
    for (i=1;i<=n;i++)
    {
        lcm = (i*lcm)/gcd(i,lcm);
    }
    printf("smallest multiple : %uL",lcm);

}

答案 3 :(得分:1)

这将为您提供从1到20的数字中的所有因素:

from collections import Counter

def prime_factors(x):
    def factor_this(x, factor):
        factors = []
        while x % factor == 0:
            x /= factor
            factors.append(factor)
        return x, factors
    x, factors = factor_this(x, 2)
    x, f = factor_this(x, 3)
    factors += f
    i = 5
    while i * i <= x:
        for j in (2, 4):
            x, f = factor_this(x, i)
            factors += f
            i += j
    if x > 1:
        factors.append(x)
    return factors

def factors_in_range(x):
    result = {}
    for i in range(2, x + 1):
        p = prime_factors(i)
        c = Counter(p)
        for k, v in c.items():
            n = result.get(k)
            if n is None or n < v:
                result[k] = v
    return result

print factors_in_range(20)

如果将这些数字乘以结果中的次数,则会得到将所有数字从1分为20的最小数字。

import operator

def product(c):
    return reduce(operator.__mul__, [k ** v for k, v in c.items()], 1)

c = factors_in_range(20)
print product(c)

答案 4 :(得分:0)

import sys

def smallestDiv(n):
    divisors = [x for x in range(1,(n+1))]    # get divisors
    for i in xrange(2520,sys.maxint,n):
        if(all(i%x == 0 for x in divisors)):
            return i

print (smallestDiv(20))

我的1.7 GHZ i7需要大约5秒钟

我的基础是C#代码: http://www.mathblog.dk/project-euler-problem-5/

答案 5 :(得分:0)

facList=[2]
prod=1

for i in range(3,1000):
    n=i
    for j in facList:
        if n % j == 0:
            n//=j
    facList.append(n)

for k in facList:
prod*=k

print(prod)

我尝试了这种方法并将我的时间与Panic上校的答案进行了比较,并且我开始在n = 200而非n = 20时大幅击败他。在我看来,他更优雅,但出于某种原因,我的速度更快。也许对算法运行时有更好理解的人可以解释原因。

答案 6 :(得分:0)

最后一个函数找到可被n整除的最小数字,因为该数字应为阶乘(n)的倍数,所以您需要具有一个计算阶乘的函数(可以通过数学方法完成)

def factoral(n):
    if n > 1:
        return n * factoral(n - 1)
    elif n >= 0:
        return 1
    else:
        return -1

def isMultiple(a, b):
    for i in range(1, b):
        if a % i != 0:
            return False
    return True

def EnkucukBul(n):
    for i in range(n, factoral(n) + 1, n):
        if isMultiple(i, n):
            return i
    return -1

答案 7 :(得分:0)

我认为Panic上校的答案很棒,但我只是想在不编辑简洁答案的情况下扩大一点。

原始解决方案是:

from fractions import gcd
def lcm(a,b):
    "Calculate the lowest common multiple of two integers a and b"
    return a*b//gcd(a,b)

>>> from functools import reduce
>>> reduce(lcm, range(1,10+1))
2520
>>> reduce(lcm, range(1,20+1))
232792560

我发现可视化N = 10时的减少量是有帮助的:

res = lcm(lcm(lcm(lcm(lcm(lcm(lcm(lcm(lcm(1, 2), 3), 4), 5), 6), 7), 8), 9), 10)

评估为:

# Evaluates lcm(1, 2)
res = lcm(lcm(lcm(lcm(lcm(lcm(lcm(lcm(lcm(1, 2), 3), 4), 5), 6), 7), 8), 9), 10)
# Evaluates lcm(2, 3)
res = lcm(lcm(lcm(lcm(lcm(lcm(lcm(lcm(2, 3), 4), 5), 6), 7), 8), 9), 10)
# Evaluates lcm(6, 4)
res = lcm(lcm(lcm(lcm(lcm(lcm(lcm(6, 4), 5), 6), 7), 8), 9), 10)
# Evaluates lcm(12, 5)
res = lcm(lcm(lcm(lcm(lcm(lcm(12, 5), 6), 7), 8), 9), 10)
# Evaluates lcm(60, 6)
res = lcm(lcm(lcm(lcm(lcm(60, 6), 7), 8), 9), 10)
# Evaluates lcm(60, 7)
res = lcm(lcm(lcm(lcm(60, 7), 8), 9), 10)
# Evaluates lcm(420, 8)
res = lcm(lcm(lcm(420, 8), 9), 10)
# Evaluates lcm(840, 9)
res = lcm(lcm(840, 9), 10)
# Evaluates lcm(2520, 10)
res = lcm(2520, 10)

print(res)
>>> 2520

以上内容涵盖了正在发生的一切。当我们使用reduce时,我们“将滚动计算应用于列表中的顺序值对”。它是从“由内而外”或在range(1, 20+1)中从左到右进行的。

我认为在这里指出您作为程序员,不要期望您将答案显而易见或显而易见就非常重要。很多聪明人花了很长时间学习了很多有关素数,最大公因数和最小公倍数等的信息。但是,作为软件工程师,您应该了解数论的基础,gcd,lcm,质数以及如何解决工具包中的问题。同样,每次解决问题时,您都不希望重新发明轮子或从数论中发现问题,但是在开展业务时,您应该在解决问题的工具包中添加工具。