使用大循环发生Python MemoryError

时间:2013-06-18 12:05:18

标签: python memory logic

我正在尝试创建一个脚本来为Project Euler解决一个问题,但它会不断返回MemoryError。我完全不知道为什么。

divisible = True
possible = dict()

for i in xrange(1, 100000000):
    for n in xrange(1, 21):
        if i%n != 0:
            divisible = False
        else:
            if i in possible:
                possible[i].append(n)
            else:
                possible[i] = [n]

        if len(possible[i]) == 20:
            print i
            break

Python似乎认为它出现在这一行possible[i] = [n]

5 个答案:

答案 0 :(得分:2)

问题出在您的行中

if len(possible[i]) == 20:

你的意思是说

if len(possible) == 20:

实际上,你的代码会继续运行 - 大概是因为循环计数太大了,一些堆栈会填满......

另外 - 虽然我不确定你想要实现什么,但是你的break命令位于最里面的循环中 - 所以你突破它,然后再次出现...并且因为长度只有20一次,你仍然卡住了。检查你的逻辑。

例如,对代码进行以下小改动会产生有用的输出(虽然我不知道它对你有用......但它可能会给你一些想法):

divisible = True
possible = dict()

for i in xrange(1, 100000000):
    for n in xrange(1, 21):
        if i%n != 0:
            divisible = False
        else:
            if i in possible:
                possible[i].append(n)
            else:
                possible[i] = [n]

    if len(possible) == 20:
        print i
        break
    else:
        print i, possible[i]

输出:

1 [1]
2 [1, 2]
3 [1, 3]
4 [1, 2, 4]
5 [1, 5]
6 [1, 2, 3, 6]
7 [1, 7]
8 [1, 2, 4, 8]
9 [1, 3, 9]
10 [1, 2, 5, 10]
11 [1, 11]
12 [1, 2, 3, 4, 6, 12]
13 [1, 13]
14 [1, 2, 7, 14]
15 [1, 3, 5, 15]
16 [1, 2, 4, 8, 16]
17 [1, 17]
18 [1, 2, 3, 6, 9, 18]
19 [1, 19]
20

编辑更仔细地阅读代码,我认为你要做的是找到具有正好20个因素的数字;因此你的情况是正确的。问题是你也存储了所有其他条款 - 这是一个非常大量的列表。如果你只是在最后一个数字之后(在休息之前所有输出都是i之后),那么你真的不需要保留所有其他条款。以下代码就是这样 - 它在我的计算机上运行得很快,现在耗时大约20 MB的内存(但还没有答案......)

divisible = True
possible = [];
biggest = 0;
bigN = 100000000;

for i in xrange(1, bigN):
    for n in xrange(1, 21):
        if i%n != 0:
            divisible = False
        else:
            if len(possible) > 0:
                possible.append(n)
            else:
                possible = [n]

    if len(possible) >= 20:
        print i
        print possible
        break
    else:
        if bigN < 1000:
            print i, possible; # handy for debugging
        if biggest < len(possible):
            biggest = len(possible);
        possible = []

计算你正在做的事情的“手动”方式是找到所有数字从1到20的主要因子;计算每个素数出现的最大次数;并采取他们的产品:

2  = 2
3  =     3
4  = 22
5  =        5
6  = 2   3
7  =          7
8  = 222
9  =     33
10 = 2      5
11 =              11
12 = 22  3
13 =                 13
14 = 2         7
15 =     3  5
16 = 2222
17 =                    17
18 = 2   33
19 =                      19
20 = 22     5

答案:(2 * 2 * 2 * 2)*(3 * 3)* 5 * 7 * 11 * 13 * 17 * 19 = 232792560

答案 1 :(得分:0)

由于大小:

导致内存错误
possible = dict()

你继续将整数推入其中,它的大小不断增长,你会得到内存错误。 仔细查看是否可以在解决方案中避免这种情况。如果答案仅需要告知因子的数量,而不是所有因素,则不要将所有值存储在列表中并计算其长度。 而是为每个数字增加计数器。 我不确定问题是什么,但可以用以下内容代替:

if len(possible[i]) == 20:
            print i
            break

可以是:

if i in possible:
            possible[i] += 1
        else:
            possible[i] = 0   
if possible[i] == 20:
                print i
                break

答案 2 :(得分:0)

快速回退信封计算。你有类似100000000整数的东西,如果你存储它们全部都是大约0.4 Gb(在C中)。当然,这些是python整数,所以每个都超过4个字节......在我的系统中,每个都是24(!)字节,这需要0.4 Gb到2.34 Gb。现在你将每个存储在最多21个列表中...这样(最多)每个指向另外21个指针。假设指向int的4byte指针,您可以看到我们已经开始消耗大量内存。

另请注意,出于性能原因,列表被过度分配。可能你使用的内存比你需要的多,因为你的列表还没有填满。

当然,你实际上并没有将它们全部存放起来,并且你有一个早期休息状态(显然)没有被击中。你可能在某处出现了逻辑错误。

答案 3 :(得分:0)

检查应该在内环之外,以便正确终止。否则,程序将永远不会在预定的退出处停止。

divisible = True
possible = dict()

for i in xrange(1, 100000000):
    for n in xrange(1, 21):
        if i%n != 0:
            divisible = False
        else:
            if i in possible:
                possible[i].append(n)
            else:
                possible[i] = [n]
    if len(possible[i]) == 20:
        print i
        break
BTW,更快的方法是找到LCM而不是像这样的强力方法。

编辑: 一种不使用记忆的变体。

divisible = True
possible = []
for i in xrange(0, 1000000000):

    count = 0
    for n in xrange(1, 21):
        if i%n != 0:
            divisible = False
        else:
            count += 1
    if count == 20:
        possible.append(i)
        print i
    else:
        print "\r", "%09d %d %d" % (i, 232792560, count),

print possible

答案 4 :(得分:0)

我想说你需要在这里改变方法。您需要符合1分钟规则的解决方案。并且在这里讨论解决方案违背了Project Euler的目的。所以我建议您考虑一种不同的方法来解决问题。一种可能在不到一秒钟内解决问题的方法。

至于内存问题,使用当前的方法,几乎​​不可能摆脱它。因此,改变方法也将解决这个问题。虽然这篇文章没有回答你的问题,但这符合Project Euler的原则!