【问题标题】:Python MemoryError occurring with large loopPython MemoryError 发生大循环
【发布时间】:2013-06-18 12:05:17
【问题描述】:

我正在尝试创建一个脚本来为我解决有关 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]

【问题讨论】:

  • 也许您分配的内存超出了计算机的处理能力。

标签: python memory logic


【解决方案1】:

问题出在你的行

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

EDIT 更仔细地阅读代码,我认为您要做的是找到正好有 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

【讨论】:

  • 不,我需要找到字典值的长度,因为我试图找到可被 20 个数字整除的键。
  • 但这正是i 是什么......这就是这个程序将返回的内容。它还将返回possible - 因素本身。尝试使用小于 20 的值,您会发现它有效(无需留胡子等待)。
  • 我不知道为什么你的代码上有;if len(possible) &gt; 0 也不起作用,因为我需要检查字典中是否真的有那个键,我们可以'不要只是假设。
  • 但我没有使用密钥...我一直在重复使用possible
  • 如果您仍然不相信这会给您答案,请将外部 for 循环更改为 for i in xrange(232792500,232792600): - 该范围包含答案,但不会永远...
【解决方案2】:

由于 : 的大小而发生内存错误

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

【讨论】:

  • 试过了,但在possible[i] = 0 线上仍然出现 MemoryError
【解决方案3】:

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

另请注意,出于性能原因,列表被过度分配。很可能您使用的内存超出了您的需要,因为您的列表未满。

当然,您实际上并没有全部存储它们,而且您有一个(显然)没有受到影响的早期中断条件。很可能你在某个地方有逻辑错误。

【讨论】:

  • possible 是一本字典。
  • @Shazer2 -- 没错。出于某种原因,我认为它说的是if i in possible[i] 或类似的东西。我想早上对我来说太早了。
  • 找出因数为 1-20 且没有余数的那个。
  • 为什么不只计算20!?还是需要第一个?
  • FWIW。没有电脑也不难计算答案:2*2*2*2*3*3*5*7*11*13*17*19
【解决方案4】:

检查应该在内循环之外才能正确终止。否则,程序将永远不会在预期退出时停止。

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

顺便说一句,找到 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

【讨论】:

    【解决方案5】:

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

    至于内存问题,以目前的方式,几乎是不可能解决的。所以改变方法也将解决这个问题。虽然这篇文章没有回答你的问题,但它符合 Project Euler 的原则!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-27
      • 2015-12-22
      • 1970-01-01
      • 2017-10-18
      • 1970-01-01
      • 2021-11-20
      • 1970-01-01
      相关资源
      最近更新 更多