代码之家  ›  专栏  ›  技术社区  ›  user1008636

该算法的时间复杂度:词梯

  •  8
  • user1008636  · 技术社区  · 5 年前

    查找从beginWord到的所有最短转换序列 结束语,这样:

    一次只能更改一个字母。每个被转换的单词必须 存在于单词列表中。请注意,beginWord不是一个经过转换的单词。

    例1:

    endWord=“齿轮”, 字表= [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]

    输出:[[“命中”,“热”,“点”,“dog”,“cog”],[“hit”,“hot”,“lot”,“log”,“cog”]]

    1) 从beginWord开始执行一个BFS,将每个字母转换成26个字母中的一个,然后查看转换后的单词是否在单词列表中,如果在,则放入队列中。

    3) 当nextWord到达endWord时,执行回溯DFS(预订购 遍历)在图上获取所有路径。

    class Solution:
        def findLadders(self, beginWord, endWord, wordList):
            """
            :type beginWord: str
            :type endWord: str
            :type wordList: List[str]
            :rtype: List[List[str]]
            """
            wordListSet = set(wordList+[beginWord])
            graph = collections.defaultdict(list)
            q = set([beginWord])    
            count = 0
            result = []
            while q:
                count +=1
                newQ = set()
                for word in q:
                    wordListSet.remove(word)
                for word in q:
                    if word == endWord:                                        
                        self.getAllPaths(graph, beginWord, endWord, result, [])
                        return result
                    for i in range(len(word)):
                        for sub in 'abcdefghijklmnopqrstuvwxyz':
                            if sub != word[i]:
                                newWord = word[:i] + sub + word[i+1:]
                                if newWord in wordListSet:
                                    graph[word].append(newWord)
                                    newQ.add(newWord)
                q = newQ
            return []
    
        def getAllPaths(self, graph, node, target, result, output):
            #This is just a backtracking pre-order traversal DFS on a DAG.
            output.append(node)
            if node==target:
                result.append(output[:])
            else:
                for child in graph[node]:
                    self.getAllPaths(graph,child, target, result, output)
                    output.pop()
    

    我的论点是:

    时间: O(26*L*N + N ),其中 L 平均长度 每一个字,以及 N 字表中的字数 . 这里最坏的情况是,转换后的每个单词恰好都在列表中,因此每个转换都需要 26 * length of word . DFS部分只是 O(N) O(L*N)

    间距:O(N)

    2 回复  |  直到 5 年前
        1
  •  5
  •   vencaslac    5 年前

    beginWord = aa,
    endWord = bb
    wordList = [aa, ab, ba, bb]
    

    你的算法会错过路径 aa -> ba -> bb . 事实上,它最多只能找到一条路。

    时间的复杂性确实 O(L * N) O(L*N) 你的图形或 wordList 占有。

        2
  •  0
  •   Charles Merriam    5 年前

    O(L * N) . 如果修复了返回所有解决方案的代码,则递归打印例程是 O(L!) .

    1. for all nodes being considered ['aaa', 'aab', ... 'zzz'] . 节点计数为26^3或27576。正在从 aaa zzz 有六个答案: aaa->zaa->zza->zzz aaa->zaa->aza->zzz , aaa->aza->zza->zzz ,等等。您将考虑所有长度的三条路径,(25+25+25) (25)或93750条路径以确保没有更短的路径。

    2. 内部循环有两种选择: for i in range(len(word)) 以及递归调用 get_all_paths() O(L*N) . 请注意 O(L * N * 26) 意思是一样的;大O符号只关心变化的规模。我还没有证明你在“获取所有路径”循环上保持线性。

    3. Dijkstra's Shortest Path . 你可以更好地为你的具体问题添加一个启发式方法。通过一个节点的总路径长度总是大于或等于到目前为止的距离加上仍然错误的字母数。在这种情况下,这意味着你已经完全联系上了 aaa (0 length)->aab (1)->abb (2)->bbb (3) 所以你避免探索 aaa (0 actual + 3 heuristic) -> aab (1 actual + 3 heuristic)

    4. here getAllPaths() 现在常规的发展速度比现在快 O(L*N)