简体   繁体   中英

Recursive function dies with Memory Error

Say we have a function that translates the morse symbols:

  • . -> -.
  • - -> ...-

If we apply this function twice, we get eg:

. -> -. -> ...--.

Given an input string and a number of repetitions, want to know the length of the final string. (Problem 1 from the Flemish Programming Contest VPW, taken from these slides which provide a solution in Haskell).

For the given inputfile

4
. 4
.- 2
-- 2 
--... 50

We expect the solution

44
16
20
34028664377246354505728

Since I don't know Haskell, this is my recursive solution in Python that I came up with:

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())

which works for the first three inputs but dies with a memory error for the last input.

How would you rewrite this in a more efficient way?

Edit

Rewrite based on the comments given:

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))

Comments on style and further improvements still welcome

Consider that you don't actually have to output the resulting string, only the length of it. Also consider that the order of '.' and '-' in the string do not affect the final length (eg ".- 3" and "-. 3" produce the same final length).

Thus, I would give up on storing the entire string and instead store the number of '.' and the number of '-' as integers.

In your starting string, count the number of dots and dashes. Then apply this:

repetitions = 4
dots = 1
dashes = 0
for i in range(repetitions):
    dots, dashes = dots + 3 * dashes, dashes + dots

Think about it why this works.

Per @Hammar (I had the same idea, but he explained it better than I could have ;-):

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]

you put the count of dots to dashes, and count of dashes to dots in each iteration...

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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM