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]