在Python中找到可以在一系列数字中平分的最小值,拼图

时间:2013-07-31 20:20:44

标签: python algorithm

我正在尝试解决下面详述的投射难题。我当前的函数适用于数字1到10,但是当我尝试1到20时,它只是永远循环而没有结果。

  

2520是可以除以1至10中的每个数字而没有任何余数的最小数字。   可以被1到20的所有数字整除的最小正数是多少?

def calculate():
    results = dict()
    target = 20
    num_to_test = 1
    while len(results) < target:
        for j in range(1, target+1):
            results[num_to_test] = True
            if num_to_test % j != 0:
                # current num_to_test failed in the 1-10, move on
                del results[num_to_test]
                break

        num_to_test += 1
    return min(results)

任何人都可以在逻辑中看到任何问题,特别是我想知道为什么它适用于10的目标,但不是20.谢谢

5 个答案:

答案 0 :(得分:5)

你的算法效率很低,但你问题的核心是你的results字典为每个整数积累了1个值,它们可以被1-20的数字整除,并且你的{{ 1}}循环试图继续前进,直到它有20个这样的数字。

这是实现这种低效算法的一种正确方法:

while

请注意,def calculate(): target = 20 candidate = 1 success = False divisors = range(1, target+1) while not success: for divisor in divisors: if candidate % divisor != 0: candidate += 1 break else: success = True return candidate 子句实际上是for循环,而不是if。来自流量控制的tutorial

  

循环语句可能有一个else子句;当循环通过列表耗尽(with for)或条件变为false(with while)时终止,但是当循环被break语句终止时,执行它。

更简洁的表达方式是:

else

它使用生成器表达式,因此candidate = 0 while not success: candidate += 1 success = all((candidate % divisor == 0 for divisor in divisors)) 可以短路并避免进行不必要的计算。

由于这是一个难题,我将继续提出更好的算法。

答案 1 :(得分:4)

实际上我对这个问题有非常有效的算法。 我不会给你代码,但我可以告诉你的方式

对于N = 10

1.计算从5到10的所有数字的所有因素:

 [[2, 3], [7], [2, 2, 2], [3, 3], [2, 5]]

2.计算列表中每个素数的最大数量

 {2: 3, 3: 2, 5: 1, 7: 1}

3.确定关键功率值的乘积

 2^3 * 3^2 * 5 * 7 = 2520

答案 2 :(得分:2)

许多其他答案都提到原始代码效率低下,但它们仍然会遍历几乎所有数字。利用lcm函数不是更有效吗?

def calculate(num, current_lcm = 1):
    if (num == 1): return current_lcm
    return calculate(num - 1, lcm(num, current_lcm))

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

def gcd(a, b):
    while b:      
        a, b = b, a % b
    return a

print calculate(20)

答案 3 :(得分:1)

不要存储所有内容,而只是在找到它时尽早返回,去掉那个结果字典,顺便说一下这根本不是最优的,只是一个清理

def calculate():
    target = 20
    num_to_test = 0
    while True:
        num_to_test += target
        if all((num_to_test % j == 0) for j in range(1,target+1)):
            return num_to_test
    return -1

此外,您不需要测试不是最大倍数的数字。它的运行速度要快20倍。

我转而使用生成器进行测试,以查看该数字是否可以被all()的nubmers从1到20整除

用于编写自己的算法而不复制一个算法的道具:)

答案 4 :(得分:1)

虽然您的算法效率非常低,但这可能有助于实现这一小改变

        if num_to_test % j = 0:
            results[num_to_test] = True
        else:
            # current num_to_test failed in the 1-10, move on
            break

不确定为什么要存放它们?也许是为了调试?

提示。最好计算结果的素因子并简单地将它们相乘。

# spoiler  






























def calculate(target):
    n = 1
    for i in range(1, target+1):
        for j in range(1, target+1):
            if (n * j) % i == 0:
                n *= j
                break
    return n