我可以更有效地搜索带有> 500除数的第一个三角形数字吗?为什么我目前的实施速度慢?

时间:2017-07-13 16:42:18

标签: python performance python-3.x math

我正在使用Project Euler problem 12

  

第一个三角形数的值超过500个除数是多少?

我确信它可以为较小的数字产生正确的答案。例如,如果我将> 500替换为== 6,则我得到的输出结果是预期的28

对于500个除数,大约两分钟执行,程序开始运行得非常慢。我相信这里的每个变量都会在每次迭代时被覆盖。它为什么慢?我已经尝试分离成函数来使用局部变量,但这并没有改善运行时间。

代码:

import sys

currentNumber, currentCalculationNumber, divisorCount, naturalNumber = 1, 1, 0, 1

while True:

    while currentCalculationNumber <= currentNumber:
        if currentNumber % currentCalculationNumber == 0:
            divisorCount += 1
        currentCalculationNumber += 1
    if divisorCount > 500:
        print ("ANSWER: " , currentNumber)
        sys.exit(0)

    naturalNumber += 1
    currentNumber += naturalNumber
    currentCalculationNumber, divisorCount = 1, 0

2 个答案:

答案 0 :(得分:3)

缓慢来自你的计算除数的蛮力方法。解决方案大约为10 ^ 8,因此您需要以10 ^ 16次的顺序遍历内部while循环:嵌套循环生成 O(n)过程。这需要一段时间。你需要更高效的东西,至少 O (n log(n))。

Project Euler的目的之一是让我们研究更有效的算法。对于这个,您可能想要使用divisor function,这将需要众多素数生成函数中的任何一个。

你应该开发一套技巧&#34;您import解决大多数问题的模块。事实上,你应该已经有一个从早期问题中产生素数的假设(假设你以某种顺序攻击它们)。如果没有,请尝试this one

答案 1 :(得分:1)

我同意@ Prune的回答,但这是你的强力算法的更快版本:

VERSION 1(使用numpy慢一点,蛮力)

import numpy as np
i = 1
f = lambda N: (N * (N + 1)) // 2
ndmax = 0

while True:
    t = f(i)
    p = np.arange(1, t + 1)
    r = np.mod(t, p)
    nd = p.size - np.count_nonzero(r) + 1
    if nd > ndmax: # track progress
        ndmax = nd
        print((i, t, nd))
    if nd > 500:
        print ("ANSWER: " , t)
        break
    i += 1

VERSION 2(快速,使用sympy的divisor_count

from sympy import divisor_count
import numpy as np
i = 1
f = lambda N: (N * (N + 1)) // 2
ndmax = 0

while True:
    t = f(i)
    nd = divisor_count(t)
    if nd > ndmax: # track progress
        ndmax = nd
        print((i, t, nd))
    if nd > 500:
        print ("ANSWER: " , t)
        break
    i += 1

有关详情,请参阅divisor_count及其中的参考资料。