【问题标题】:What's wrong with my python solution to Project Euler #12?我对 Project Euler #12 的 python 解决方案有什么问题?
【发布时间】:2012-02-07 19:21:26
【问题描述】:

可能的剧透警告

我花了很长时间试图改进这个算法并找出问题所在,但我似乎无法弄清楚为什么输出的答案不正确。

我正在尝试解决Project Euler #12,以获得具有超过 500 个除数的最小三角数,但它说我的答案不正确。

这是我的 Python 代码:

import time

# function to get the number of divisors
def div(n):
    d=2
    for i in range(2,int(n**.5)+2):
        if (n % i) == 0:
            d += 1
    return d

start = time.time()

w = True
n=m=1
while w:
    n += 1
    s = (n*(n+1))/2 # nth triangle number
    r = div(s)
    if r > m:
        m = r
        print s,"has",r,"divisors"
        if r > 500:
            w = False

print "Solved in",((time.time()-start)*1000),"milliseconds"

该代码的输出是这样的(在 66 秒内):

3 has 2 divisors
6 has 4 divisors
36 has 6 divisors
120 has 9 divisors

...

76576500 has 289 divisors
103672800 has 325 divisors
236215980 has 385 divisors
842161320 has 513 divisors
Solved in 65505.5799484 milliseconds

但是,如果我将 842161320 输入到 Project Euler 问题中,它会说它不正确。

我做错了什么?

【问题讨论】:

  • 您的初始输出与问题陈述中的示例输出不匹配 - 28 应该是第一个具有六个除数的三角形数。
  • @Odomontois - 我知道,但看看你是否search project euler 目前有 4554 个结果,所以我并不孤单。到目前为止,我也完成了所有这些工作,甚至没有使用任何其他网站,但我真的被困在了这个网站上
  • 您可能想查看我为某些工具创建的“eulerlib”。

标签: python algorithm math


【解决方案1】:

我看到两个错误:

  • 您的div 函数已损坏:div(24) == 5,而它应该是 8
  • 你的第一个三角数应该是3,虽然它应该是1

您可以像这样实现一个有效的div

import math
def divisors(n):
  return sum(1 for x in range(1, n+1) if n % x == 0)

此外,该代码效率低下,一些改进建议是:

不要使用公式计算nth 三角数,而是使用滚动和:

import itertools

s = 0
for i in itertools.count(1):
  s += i
  if div(s) > 500:
    print s
    break

另外,请使用prime factors to calculate the number of divisors。您可以创建主要因素缓存以获得最佳性能。

【讨论】:

  • 对 - 没有出现那个 1 的原因是我设置了 n=1,所以它开始有点提前。我最初使用的是滚动总和,但将其更改为第 n 个公式。唯一剩下的问题是 div 函数
  • @Alex:我链接的维基百科文章告诉你,除数的数量可以使用数字的素数表示来计算。假设你有素因数p1**x1 * p2**x2 * p3**x3,那么除数的数量是(x1+1)(x2+1)(x3+1)。您还可以使用蛮力方法,只需检查从 1 到 sqrt(n) 的每个数字是否是除数(请参阅我的答案以获取建议)。
  • Niklas - 现在使用蛮力并将 1 的值简单地加倍到 sqrt(n) 并且它工作得很好(除了返回 2 的 1 !)但它现在完成了整个事情只有 6 秒 - 看我的答案
  • @Alex:很高兴我能帮上忙 :) 如果我的回答有帮助,我们邀请您投票并接受。顺便说一句,您的 div 函数对所有具有奇数除数的数字(也称为平方数 1、4、9、16...)返回错误的结果
【解决方案2】:

您低估了除数的总数。例如,36 有 9 个除数:1、2、3、4、6、9、12、18、36。确实,该算法只需要测试小于sqrt(n) 的数字即可找到所有除数,但您仍然需要在计数中包含隐含的“大”除数。

【讨论】:

    【解决方案3】:

    已解决

    在 Niklas 的帮助下,更改了我的 div 方法,我得到了答案。而且,现在只需要我之前算法的 8% 的时间。

    算法现在看起来像这样:

    import time
    import itertools
    
    def div(n):
        d=0
        for i in range(1,int(n**.5)+1):
            if (n % i) == 0:
                d += 1
        return 2*d
    
    start = time.time()
    
    s = m = 0
    for i in itertools.count(1):
        s += i
        r = div(s)
        if r > m:
            m = r
            print s,"has",r,"factors"
            if div(s) > 500:
                break
    
    print "Solved in",((time.time()-start)*1000),"milliseconds"
    

    【讨论】:

    • 您的div() 函数不正确(尝试div(4)div(9)
    • 是的,如果n 是某个数字的平方,则该数字在div() 中计数两次
    • @BlueRaja-DannyPflughoeft 它在这种情况下有效 - 我知道它并不完全正确,但它解决了难题
    猜你喜欢
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    • 2022-11-29
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 1970-01-01
    相关资源
    最近更新 更多