Python 递归函数因内存错误而死亡

Python 递归函数因内存错误而死亡,python,algorithm,recursion,Python,Algorithm,Recursion,假设我们有一个翻译莫尔斯符号的函数: ->-. -->..- 如果我们应用此函数两次,我们得到例如: ->-.->..-. 给定一个输入字符串和多次重复,希望知道最终字符串的长度。(VPW中的问题1,摘自该问题,在Haskell中提供了解决方案) 对于给定的输入文件 4 . 4 .- 2 -- 2 --... 50 我们期待解决办法 44 16 20 34028664377246354505728 因为我不认识Haskell,所以这是我用Python提出的递归解决方案: def enc

假设我们有一个翻译莫尔斯符号的函数:

  • ->
    -.
  • -
    ->
    ..-
如果我们应用此函数两次,我们得到例如:

->
-.
->
..-.

给定一个输入字符串和多次重复,希望知道最终字符串的长度。(VPW中的问题1,摘自该问题,在Haskell中提供了解决方案)

对于给定的输入文件

4
. 4
.- 2
-- 2 
--... 50
我们期待解决办法

44
16
20
34028664377246354505728
因为我不认识Haskell,所以这是我用Python提出的递归解决方案:

def encode(msg, repetition, morse={'.': '-.', '-': '...-'}):
    if isinstance(repetition, str):
        repetition = eval(repetition)
    while repetition > 0:
        newmsg = ''.join(morse[c] for c in msg)
        return encode(newmsg, repetition-1)
    return len(msg)


def problem1(fn):
    with open(fn) as f:
        f.next()
        for line in f:
            print encode(*line.split())
它适用于前三个输入,但最后一个输入因内存错误而消失

您将如何以更有效的方式重写此内容

编辑

根据给出的注释重写:

def encode(p, s, repetition):
    while repetition > 0:
        p,s = p + 3*s, p + s
        return encode(p, s, repetition-1)
    return p + s


def problem1(fn):
    with open(fn) as f:
        f.next()
        for line in f:
            msg, repetition = line.split()
            print encode(msg.count('.'), msg.count('-'), int(repetition))

关于样式和进一步改进的评论仍然是受欢迎的

请考虑,您实际上不必输出结果字符串,只需输出其长度。还考虑字符串中的“.'”和“--”的顺序不影响最终长度(例如,“-- 3”和“-- 3”)产生相同的最终长度。


因此,我将放弃存储整个字符串,而是将“.”的数量和“-”的数量存储为整数。

在每次迭代中,将点的计数设置为破折号,将破折号的计数设置为点

def encode(dots, dashes, repetitions):
    while repetitions > 0:
        dots, dashes = dots + 3 * dashes, dots + dashes
        repetitions -= 1

    return dots + dashes

def problem1(fn):
    with open(fn) as f:
        count = int(next(f))
        for i in xrange(count):
            line = next(f)
            msg, repetition = line.strip().split()
            print encode(msg.count('.'), msg.count('-'), int(repetition))

在起始字符串中,计算点和破折号的数量。然后应用以下方法:

repetitions = 4
dots = 1
dashes = 0
for i in range(repetitions):
    dots, dashes = dots + 3 * dashes, dashes + dots
想想为什么会这样。

Per@Hammar(我有同样的想法,但他解释得比我好;-):


将其转换为while循环。基本上,您正在达到递归限制,因此如果删除递归,您的问题应该会消失。@ThomasK完全正确-您必须在不实际创建此字符串的情况下解决问题。它将总共占用34万亿千兆字节。即使没有任何递归开销,这也会中断。不要在任何地方使用eval。使用int来解码重复!顺便说一下,到目前为止概述的解决方案在重复次数上都具有线性复杂性。有一个更有效的解决方案,使用平方矩阵求幂,这将允许您有效地解决这一问题,进行大量重复。这是一个很好的练习:)@BioGeek:你可以将更新
p,s=p+3*s,p+s
作为2x2矩阵
a=[[1,3],[1,1]]
的乘积,通过列向量
[p,s]
。现在,不必将矩阵乘以向量
n
乘以(O(n)矩阵向量乘法),您可以通过平方(O(logn)矩阵矩阵乘法)的幂运算高效地计算矩阵
A^n
,然后将其乘以
[p,s]<代码> <代码> n>代码>步骤。还考虑一个字符串3408663672463545057字符是21个Zeta表。如果你读幻灯片,这正是Haskell解决方案。@ ToMask-为什么是21而不是34(或者如果你使用二进制前缀)30?@ DaviDrordns:我用的是二进制前缀,但我做了一个排错。是29。(从技术上讲,它们是Zebibytes,但我从未听说有人在实际讨论中使用*bibytes)
from sympy import Matrix

t = Matrix([[1,3],[1,1]])

def encode(dots, dashes, reps):
    res = matrix([dashes, dots]) * t**reps
    return res[0,0] + res[0,1]