【问题标题】:Need help understanding how to implement memoization需要帮助了解如何实现 memoization
【发布时间】:2014-06-03 08:05:31
【问题描述】:

我正在尝试完成我在实现记忆化方面的第一个练习,但我不知道如何解决这个问题:

我有一个函数可以将输入文本包装成指定的行长,然后打印结果。

def wrap(input, lineSpaces):
    if len(input) <= lineSpaces:
        return input
    temp = input.rfind(" ", 0, lineSpaces - 1)
    if temp == -1:
        return input
    else:
        return input[:temp+1]+'\n'+wrap(input[temp+1:], lineSpaces)

# I/O
list = []
M = int(raw_input())
for i in xrange(0, M):
    lineSpaces = int(raw_input())
    input = raw_input()
    list.append(wrap(input, lineSpaces))

for i in list:
    print i+"\n"

我目前的记忆尝试:

def wrap(input, lineSpaces):
    if len(input) <= lineSpaces:
        return input
    temp = input.rfind(" ", 0, lineSpaces - 1)
    if temp == -1:
        return input
    else:
        return input[:temp+1]+'\n'+wrap(input[temp+1:], lineSpaces)

# I/O
inputList = []
lineSpacesList = []
unmemoizedOutput = []
M = int(raw_input())
memo = {}

for i in xrange(0, M):
    lineSpacesList.append(int(raw_input()))
    inputList.append(raw_input())
    unmemoizedOutput.append(wrap(inputList[i], lineSpacesList[i]))

for i in unmemoizedOutput:
    if not i in memo:
        for j in xrange(0, M):
            memo[i] = i + wrap(inputList[j], lineSpacesList[j])
    print memo[i]+"\n"

我没有得到我想要的输出。当我输入时:

3
20
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. A
30
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cu
36
Lorem ipsum dolor sit amet,

我明白了:

Lorem ipsum dolor 
sit amet, 
consectetuer 
adipiscing elit. ALorem ipsum dolor sit amet,

Lorem ipsum dolor sit amet, 
consectetuer adipiscing 
elit. Aenean commodo ligula 
eget dolor. Aenean massa. CuLorem ipsum dolor sit amet,

Lorem ipsum dolor sit amet,Lorem ipsum dolor sit amet,

这显然是错误的。看起来我的“记忆”版本唯一要做的就是将最终输出附加到其他所有输出。所以,我认为我对如何为这个函数实际实现记忆的理解完全不正确。有人可以指出我正确的方向吗?

【问题讨论】:

  • 顺便说一下,这个函数并不特别适合记忆。记忆对dynamic programming 特别有用,您可以在其中一遍又一遍地进行相同的递归调用。在那里,它可以将指数时间算法变成线性时间。在这里,递归没有利用备忘录,我不知道你是否可能会尝试重复换行相同的文本。 (也许你是。我想这取决于应用程序。)

标签: python algorithm recursion memoization


【解决方案1】:

记忆是你在实现一个功能时所做的事情,而不是在使用它时。当你产生一个输出时,你记录下这个调用的输入对应于你产生的输出。当你接到一个电话时,你检查你是否已经为你收到的输入存储了一个输出,如果有,你就使用存储的输出。它看起来像这样:

_memodict = {}
def memoized_function(input):
    try:
        return _memodict[input]
    except KeyError:
        # do what you would have normally done
        _memodict[input] = output
        return output

或者像这样:

import functools
def memoize(function):
    _memodict = {}

    # This decorator just makes the new function look a bit nicer
    @functools.wraps(function)
    def wrapped(*args):
        try:
            return _memodict[args]
        except KeyError:
            output = _memodict[args] = function(*args)
            return output
    return wrapped

@memoize
def function(input):
    # Exactly what you would have written normally

【讨论】:

  • 感谢您的回复,这更有意义。我想我现在有了一些东西——除了确认我有预期的输出、打印语句调试等之外,你知道有什么方法可以确保记忆功能确实有效吗?
  • @user3681725:确保递归调用也命中了备忘录,方法是使用之前递归调用中可能出现的输入之一调用 memoized 函数并验证该函数是否采用快速路径。如果你写了一个 memoization 装饰器,你可以尝试使用朴素的递归斐波那契实现(fib(n-1) + fib(n-2))。 Memoized,该实现应该能够处理像fib(200) 这样的输入。如果记忆不起作用,那么这样的输入将永远无法完成。
  • 好的,好主意。看起来它在fib(124) 及以下的所有东西上都运行得很快,但任何超过它的东西都会导致RuntimeError: maximum recursion depth exceeded。您认为我的原始功能需要修复吗?
  • @user3681725:我不确定额外的堆栈帧来自哪里。这可能只是您的实现与我的实现之间的良性差异,也可能是一个问题。我倾向于“不是问题”。
  • 太棒了。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2021-11-16
  • 2011-10-26
  • 1970-01-01
  • 2017-06-19
  • 2016-05-03
  • 1970-01-01
  • 2021-01-18
  • 1970-01-01
相关资源
最近更新 更多