[LeetCode]126. Word Ladder II

126. Word Ladder II

题意:从给定的字符串数组中,选择从起始字符串到终点字符串的路径。

回朔

TLE

class Solution(object):
    def findLadders(self, beginWord, endWord, wordList):
        """
        :type beginWord: str
        :type endWord: str
        :type wordList: List[str]
        :rtype: List[List[str]]
        """
        def backtracking(cur, path):
            if cur == endWord:
                if not res:
                    res.append(list(path))
                elif len(path) < len(max(res, key=lambda x:len(x))):
                    del res[:]
                    res.append(list(path))
                elif len(path) == len(max(res, key=lambda x:len(x))):
                    res.append(list(path))
                return
            for i in range(len(beginWord)):
                for j in range(26):
                    char = chr(ord('a') + j)
                    new_word = cur[:i] + char + cur[i + 1:]
                    if new_word in wordList and new_word not in visited:
                        path.append(new_word)
                        visited.add(new_word)
                        backtracking(new_word, path)
                        path.pop()
                        visited.remove(new_word)
        res = []
        visited = {beginWord, }
        backtracking(beginWord, [beginWord,])
        return res

总结:上面的代码必须把所有的路径都求解出来,取最小值,需要考虑到每种情况,也就是在DFS中,开的分支太多,时间复杂度相当高。

Two BFS(图论)

这道题目可以看作是一个无向图,求起始结点到终点的最短距离,那既然如此,可以使用Dijkstra来找最短路径,边的权值都设置为1,其实并没有必要,在这种情况中直接使用BFS就可以求最短路径,但为了再进行优化,使用两个BFS,一个从头搜,一个从尾搜,分别纪录路径,直到它们两个搜索出来的存在重叠的结点,说明它们是可达的,最后生成纪录下来的路径。

import collections
class Solution(object):
    # Solution using double BFS
    def findLadders(self, begin, end, words_list):
        # 生成路径
        def construct_paths(source, dest, tree):
            if source == dest:
                return [[source]]
            return [[source] + path for succ in tree[source]
                    for path in construct_paths(succ, dest, tree)]
        # 添加路径,形成一个图
        def add_path(tree, word, neigh, is_forw):
            # 保证不会重复加入字符串,造成双方均可到达的情况
            if is_forw:
                tree[word] += neigh,
            else:
                tree[neigh] += word,
        # start_set是从起始字符串开始进行搜索,end_set是从终止字符串开始搜索
        def two_bfs(start_set, end_set, tree, is_forw, words_set):
            if not start_set: return False
            # 保证start_set长度最小
            if len(start_set) > len(end_set):
                return two_bfs(end_set, start_set, tree, not is_forw, words_set)
            # 删除访问过的结点
            for word in (start_set | end_set):
                words_set.discard(word)
            next_set, done = set(), False
            while start_set:
                word = start_set.pop()
                for c in set('abcdefghijklmnopqrstuvwxyz'):
                    for index in range(len(word)):
                        neigh = word[:index] + c + word[index + 1:]
                        # 如果字符串存在于end中,说明end已经访问过,那么此时构成一条路径
                        if neigh in end_set:
                            done = True
                            add_path(tree, word, neigh, is_forw)
                        # 如果该字符串都没有被访问过,也加入到路径中
                        if not done and neigh in words_set:
                            next_set.add(neigh)
                            add_path(tree, word, neigh, is_forw)
            return done or two_bfs(next_set, end_set, tree, is_forw, words_set)
        tree, path = collections.defaultdict(list), [begin]
        two_bfs({begin}, {end}, tree, True, set(words_list))
        return construct_paths(begin, end, tree)
posted @ 2017-08-20 17:42  banananana  阅读(203)  评论(0)    收藏  举报