【问题标题】:How to use dynamic programming to split string into words? (Python, recursion, memoization)如何使用动态编程将字符串拆分为单词? (Python、递归、记忆化)
【发布时间】:2014-08-20 17:48:05
【问题描述】:

我正在尝试编写一段动态编程代码,允许我将字符串拆分为有效单词(有效性由字典查找确定)。

如果字符串不能拆分成有效的单词,我想返回''。

#

这是我的代码的第一个版本:

dictionary = {'cat':1,'hat':1,'in':1}

def memoize(f):
    cache = {}
    def memoize_function(*args):
        if args[0] not in cache:
            cache[args[0]] = f(*args)  # compute and cache result
        return cache[args[0]]
        memoize_function.cache = cache  
    return memoize_function

@memoize
def splitintowords_version1(mystring, word_list):
    if len(mystring) < 1:
        return word_list
    else:
        for i in range(len(mystring)):
            current_word = mystring[:i+1]
            remaining_word = mystring[i+1:]
            if current_word in dictionary:
                word_list = word_list + current_word + ' ' 
                return splitintowords_version1(remaining_word, word_list)
            if i == len(mystring)-1 and current_word not in dictionary:
                word_list = ''
                return word_list

虽然严格来说,代码有效,但我知道它没有正确使用动态编程,因为即使字符串越来越短,也会传递完整的单词列表。例如调用 splitintowords_version1('catinhat') 后,splitintowords_version1.cache 包含以下废话:

{'':'戴帽子的猫'}

#

然后我重写了程序:

@memoize                
def splitintowords_version2(mystring):
    if len(mystring) < 1:
        return ''
    else:
        for i in range(len(mystring)):
            current_word = mystring[:i+1]
            remaining_word = mystring[i+1:]
            if current_word in dictionary:
                return current_word + ' ' + splitintowords_version2(remaining_word)
            if i == len(mystring)-1 and current_word not in dictionary:
                return ''

此版本适当地缓存了值,但它为 splitintowords_version2('catinhata') 返回了不正确的值。它返回'cat in hat',而不是''。

我觉得我只缺少最后一块来正确编写代码。有人可以帮我吗?

谢谢!

【问题讨论】:

  • 顺便说一句,这不是作业。
  • 您的memoize() 函数似乎只关闭了第一个参数。这意味着如果你用它来包装一个带有多个参数的函数,它会错误地返回一个仅基于第一个参数的缓存返回值,即使第二个参数不同。
  • 但我希望缓存以字符串为键,而不是单词列表。希望缓存会读取如下内容: {'cathat':'cat hat', 'inhat':'in hat'}
  • 这个函数可能没问题,只是让你知道你不能将它应用到任何随机函数并期望它能够工作。
  • 好的,谢谢 :) 关于如何修改我的代码以产生适当的输出的任何建议?

标签: python recursion memoization


【解决方案1】:

您描述的行为是由于您在splitintowords_version2 中使用了递归。

如果在字典中找不到字符串的最后一个字符,则返回''。然而,这会被添加到之前的结果中 (current_word + ' ' + splitintowords_version2(remaining_word))。因此,在您的示例中,返回的'' 被简单地添加到已经拆分的"cat in hat" 以产生"cat in hat "。相反,您必须检查递归的返回值是否为空,并在需要时返回一个空字符串。 然而,这还不够,因为splitintowords_version2 为空输入字符串返回''。您可以通过为空字符串返回另一个值或无法拆分字符串来轻松解决此问题(在以下示例中,我为空字符串返回 ' ' 而不是 '',因此您可能想要剥离之后使用string.strip 的空白):

@memoize                
def splitintowords_version2(mystring):
    if len(mystring) < 1:
        return ' '
    else:
        for i in range(len(mystring)):
            current_word = mystring[:i+1]
            remaining_word = mystring[i+1:]
            if current_word in dictionary:
                remaining_split = splitintowords_version2(remaining_word)
                if len(remaining_split) > 0:
                    return current_word + ' ' + remaining_split
                else:
                    return '' # Last part was not in the dictionary.
            if i == len(mystring) - 1 and current_word not in dictionary:
                return ''

如果字符串无法拆分,另一种方法可能是返回None,并(如果需要)将其包装到另一个函数中,该函数在最终结果中转换None(不是在调用之间)回到一个空字符串。为此,请将'' 替换为None,并将len(remaining_split) &gt; 0 勾选为remaining_split != None

【讨论】:

  • 等等,这不起作用,因为 splitintowords_version2('catinhat') 也返回 ''。
  • 啊,是的(刚刚注意到)。这是因为 splitintowords_version2 还为空字符串返回 ''(现在正在修复...)
猜你喜欢
  • 2017-03-17
  • 2011-07-15
  • 2010-10-15
  • 2011-05-20
  • 2015-07-30
  • 1970-01-01
  • 2020-12-10
  • 2011-06-12
  • 1970-01-01
相关资源
最近更新 更多