Euler项目23 - 无论我做什么,我的回答都太大了

时间:2016-09-10 12:02:14

标签: python

问题23要求所有数字的总和“不是两个丰富的数字之和”。我们只需要检查小于28123的数字。如果其适当的除数总和大于n的整数,则整数n是丰富的。这是从1 + 2 + 3 + 4 + 6 = 16> 1开始的第一个数。 12.这使得24是最小的数字,它是2个丰富数字的总和,所以我们希望将它从总和中排除。

这是我的python代码,我尝试了许多变体,但使用相同的想法:

import math

def divisors_of(n):
    divs=[1]
    for i in range(2,int(math.sqrt(n))+1):
        if i**2 == n:
            divs.append(i)
        elif n%i == 0:
            divs.append(i)
            divs.append(n//i)
    return divs

def is_abun(n):
    return sum(divisors_of(n))>n

numbers=[i for i in range(1,28123)]

for i in numbers:
    for j in range(1,i):
        if is_abun(j) and is_abun(i-j):
         numbers.remove(i)
         break

print(sum(numbers))

这个想法很简单,如果j和i-j是丰富的数字,那么当然j +(i-j)= i是大量数字的总和,所以我从我的数字列表中删除它。然后我总结所有剩余的数字。我不知道这怎么可能失败。然而,结果应该是(来自另一个来源)4179871,而我总是在197711987的球场得到一些东西,这个数字超过了47倍。

我真的无法理解这是如何无法生成正确的结果。必须有一些线路没有做我认为的那样,但这里的一切只是太简单让我对它们产生怀疑。我认为最可能的错误是计算丰富的数字,但我几乎完全确定该部分是正确的(如果我得到的代码是生成一个小于28123的丰富数字列表,我得到一个长度为6965的列表,这是多少数量少于28123 WolframAlpha声称的数字。

1 个答案:

答案 0 :(得分:3)

问题是您在迭代时修改列表numbers。这样可以减少您预期的数量。

你应该迭代它的一个副本:

for i in list(numbers):
    for j in range(1,i):
        if is_abun(j) and is_abun(i-j):
         numbers.remove(i)
         break

要了解正在发生的事情,请考虑以下事项:

>>> numbers = list(range(10))
>>> for i in numbers:
...     if i%2 == 0:
...         numbers.remove(i)
...     print(i)
... 
0
2
4
6
8

正如您所看到的,for循环仅迭代偶数。那是因为上面的for循环大致等同于以下内容:

i = 0
while i < len(numbers):
    number = numbers[i]
    if number % 2 == 0:
        numbers.remove(number)
    print(number)
    i += 1

因此,当您第一次拥有i = 0并因此number = 0时,您会从0移除numbers,所以现在您拥有numbers = [1,2,3,4,..., 9]。请注意值1最终位于0的位置,所以下一次迭代我们有i = 1numbers[1] == [1,2,3,4,...,9][1] == 2所以我们跳过了数字1

每次删除号码时,列表都会被修改,如果此修改导致项目向左移动,则实际上是在跳过它们。这就是你想迭代列表的副本的原因:这样对原始列表的修改不会影响迭代期间“产生”的数字。

相关问题