Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
查找列表中其他单词组成的最长单词的python代码的时间复杂性(后续)_Python_Algorithm_Recursion_Time Complexity_Memoization - Fatal编程技术网

查找列表中其他单词组成的最长单词的python代码的时间复杂性(后续)

查找列表中其他单词组成的最长单词的python代码的时间复杂性(后续),python,algorithm,recursion,time-complexity,memoization,Python,Algorithm,Recursion,Time Complexity,Memoization,我知道已经提出并解决了一个类似的问题(),但我还有一个后续问题 我有以下问题, # Given a list of words, find the longest word made of other words in the list. # Example: [cat, banana, dog, nana, walk, walker, dogwalker] # Result: dogwalker 我在Python 3中有以下实现: def find_longest_word(list_wor

我知道已经提出并解决了一个类似的问题(),但我还有一个后续问题

我有以下问题,

# Given a list of words, find the longest word made of other words in the list.
# Example: [cat, banana, dog, nana, walk, walker, dogwalker]
# Result: dogwalker
我在Python 3中有以下实现:

def find_longest_word(list_words):
    list_words = sorted(list_words, key=lambda x:len(x))[::-1]
    for elem in list_words:
        set_remaining = set(list_words) - set([elem])
        if find_if_composite(elem, set_remaining, {}):
            return elem
    return None

def find_if_composite(s, set_):
    n = len(s)
    if len(set_) == 0 or n == 0:
        return False
    if s in set_:
        return True
    for i in range(1, n+1):
        this_s = s[:i]
        if this_s in set_:
            if find_if_composite(s[i:], set_): # assuming that I can reuse the string
                return True
    return False
从前面的答案中我们知道,这段代码在O(N!)中运行,其中N是字符串的大小(如果我是正确的话)

我的问题是:有没有办法提高时间复杂度(例如,使用备忘录)?若否,原因为何?如果是,如何进行?我尝试了下面的代码,但在递归调用过程中,它似乎从未命中备忘录

def find_if_composite_memo(s, set_, memo):
    n = len(s)
    if len(set_) == 0 or n == 0:
        return False
    if s in memo:
        return memo[s]
    if s in set_:
        return True
    for i in range(1, n+1):
        this_s = s[:i]
        if this_s in set_:
            if find_if_composite_memo(s[i:], set_, memo):
                memo[s] = True
                memo[s[i:]] = True
                return True
    memo[s] = False
    return False
测试,使用

b = ["cat", "banana", "dog", "nana", "walk", "walker", "dogwalker", "dogwalkerbanana"]
print(find_longest_word(b))

只有当您有完整的解决方案时,才能使用备忘录。 由于您按长度顺序对列表进行排序,因此您的第一个完整解决方案就是所需的答案。 因此,你永远不会使用你的备忘录

我在你的记忆程序中添加了一些跟踪,并对测试进行了一些增强:

def find_if_composite_memo(s, set_, memo):
    print "ENTER", s, '\t', memo
    n = len(s)
    if len(set_) == 0 or n == 0:
        return False
    if s in memo:
        print "Found", s, memo[s]
        return memo[s]
    if s in set_:
        return True
    for i in range(1, n+1):
        this_s = s[:i]
        if this_s in set_:
            if find_if_composite_memo(s[i:], set_, memo):
                memo[s] = True
                memo[s[i:]] = True
                print "Add", memo
                return True
    memo[s] = False
    return False

b = ["cat", "banana", "dog", "nana",
     "walk", "walker",
     "dogcat", "dogwalker",
     "dogwalkerbanana",
     "catwalkerbanana-FAIL"]
print(find_longest_word(b))
输出:

ENTER catwalkerbanana-FAIL  {}
ENTER walkerbanana-FAIL     {}
ENTER erbanana-FAIL     {}
ENTER banana-FAIL   {'erbanana-FAIL': False}
ENTER -FAIL     {'erbanana-FAIL': False}
ENTER dogwalkerbanana   {}
ENTER walkerbanana  {}
ENTER erbanana  {}
ENTER banana    {'erbanana': False}
Add {'walkerbanana': True, 'erbanana': False, 'banana': True}
Add {'walkerbanana': True, 'erbanana': False, 'dogwalkerbanana': True, 'banana': True}
dogwalkerbanana
你看到问题了吗?使用“猫步舞步失败”,您有可能录制“猫步舞步”、“猫步舞步舞步”和“步行舞步舞步”,但不要利用这一点。最后一个将为您节省一些搜索时间

至于改进整体算法,你可以考虑SE的站点。

我希望,如果您使用以下一些方法,您可以做得更好:

(1) When you fail to find the present top-level word **elem** as a composite, you can remove it from the word list entirely.  Don't keep it in set_remaining: since it's at least as long as any other word in the list, it cannot be a component.
(2) In **find_if_composite**, you go through a lot of pain to determine whether any beginning substring of **s** is in the word_list.  I think you can speed this up: use **s.startswith(word)** on each word in the list.  
(3) If the list has enough composite hits to matter, examine your memoization algorithm carefully.  Figure out what is and is not worth saving, and write the pseudo-code to handle only the time-saving parts.  Remember that, in working from largest to smallest, you're going to short-circuit a lot of cases.  In this test set, though, finding "walkerbanana" the first time seen would save a recursion later.
还可以寻找使用其他索引的好位置,例如索引(子字符串搜索)