美文网首页
LintCode 121. 单词接龙 II

LintCode 121. 单词接龙 II

作者: CW不要无聊的风格 | 来源:发表于2020-07-29 18:22 被阅读0次

    题目描述

    给出两个单词(startend)和一个字典,找出所有从startend的最短转换序列。

    变换规则如下:

    1. 每次只能改变一个字母。

    2. 变换过程中的中间单词必须在字典中出现。

    注意事项

    所有单词具有相同的长度。

    所有单词都只包含小写字母。

    题目确保存在合法的路径。


    测试样例

    输入:start = "a",end = "c",dict =["a","b","c"]

    输出:[["a","c"]]

    解释:

    "a"->"c"

    输入:start ="hit",end = "cog",dict =["hot","dot","dog","lot","log"]

    输出:[["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]

    解释:

    1."hit"->"hot"->"dot"->"dog"->"cog"

    2."hit"->"hot"->"lot"->"log"->"cog"

    第一个序列的字典序小于第二个。


    解题思路

    首先从end开始反向构建层级关系,提供可行的所有路径,既然是层级关系,那么就很自然会使用BFS

    在BFS对每层进行搜索时,需要记录下搜索的下一层每个单词距end的距离,可用一个dict来记录,此处记为distance,key就是搜索到的下一层单词,value是对应距end的距离,设置为上一层单词距离加1。另外,搜索到的词还需要满足之前没有被distance记录,即不在distance的key中,避免构建循环路径。

    这里讲下搜索单词的方法:

    对单词的每个字母位置依次进行替换,每个位置有25种可能(26个字母除去当前字母),然后判断替换后的词是否在字典中。如果是,则作为搜索到的下一个单词。

    BFS构建完层级关系后,就从start开始进行DFS,搜寻符合要求的每条目标路径。DFS搜索单词的方法如同上述,但是需要外加一个条件——搜索到的下个词距离end必须比当前这个词更近1。最后搜索至当前的词为end后将整条路径加入结果集并终止搜索。

    另外,还有一种搜索单词的方法:

    对字典中的每个单词,将其每个位置的字母用'%'代替,构建一个patten,作为key,value设置为原来的这个单词,将这样的一个个key-value对存到一个dict中,之后在BFS和DFS中就通过这个dict来查询搜索的词,而不再使用原先的字典。


    代码

    1.

    from collections import deque

    class Solution:

        """

        @param: start: a string

        @param: end: a string

        @param: dict: a set of string

        @return: a list of lists of string

        """

        L = sys.maxsize

        def findLadders(self, start, end, dict):

            if len(start) == 1 and len(end) == 1:

                return [[start, end]]

            # 记录路径中各个词到end的距离       

            dis = {}

            # 将start,end加入字典,注意不要写成.union(start, end)!

            dict = dict.union([start, end])

            # 从end开始反向进行宽度优先搜索,建立层级关系

            self._BFS(end, dis, dict)

            result = []

            # 从start开始进行深搜,寻找每条目标路径

            self._DFS(start, end, dis, dict, [start], result)

            return result

        def _DFS(self, cur, target, dis, dic, path, result):

            if cur == target:

                result.append(path)

                return

            for next_word in self._get_next_words(cur, dic):

                # 必须满足下一个词的距离end比当前词距离end更近1

                if dis[cur] - dis[next_word] == 1:

                    self._DFS(next_word, target, dis, dic, path + [next_word], result)

        def _BFS(self, begin, dis, dic):

            dis[begin] = 0

            queue = deque([begin])

            while queue:

                cur = queue.popleft()

                for next_word in self._get_next_words(cur, dic):

                    # 注意下一个词需要未被dis记录

                    # 避免构建循环路径

                    if next_word not in dis:

                        dis[next_word] = dis[cur] + 1

                        queue.append(next_word)

        def _get_next_words(self, word, dic):

            """寻找下一个可能的词,其必须在字典中"""

            next_words = []

            for i in range(len(word)):

                for c in 'abcdefghijklmnopqrstuvwxyz':

                    if c == word[i]:

                        continue

                    next_word = word[:i] + c + word[i + 1:]

                    if next_word in dic:

                        next_words.append(next_word)

            return next_words

    2.

    from collections import deque

    class Solution:

        """

        @param: start: a string

        @param: end: a string

        @param: dict: a set of string

        @return: a list of lists of string

        """

        L = sys.maxsize

        def findLadders(self, start, end, dict):

            if len(start) == 1 and len(end) == 1:

                return [[start, end]]

            # 将start,end加入字典,注意不要写成.union(start, end)!

            dict = dict.union([start, end])

            # 对字典中每个词的替换模式都构建对应的映射关系

            # 将每个词的各个位置替换为'%'作为key,value是该词本身

            maps = self._build_maps(dict)

            # 从end开始反向进行宽度优先搜索,建立层级关系

            dis = self._BFS(end, maps)

            result = []

            # 从start开始进行深搜,寻找每条目标路径

            self._DFS(start, end, dis, maps, [start], result)

            return result

        def _build_maps(self, dic):

            maps = {}

            for word in dic:

                for i in range(len(word)):

                    pattern = word[:i] + '%' + word[i + 1:]

                    if pattern in maps:

                        maps[pattern].add(word)

                    else:

                        maps[pattern] = set([word])

            return maps

        def _DFS(self, cur, target, dis, maps, path, result):

            if cur == target:

                result.append(path)

                return

            for next_word in self._get_next_words(cur, maps):

                # 必须满足下一个词的距离end比当前词距离end更近1

                if dis[cur] - dis[next_word] == 1:

                    self._DFS(next_word, target, dis, maps, path + [next_word], result)

        def _BFS(self, begin, maps):

            # 记录路径中各词到目标的距离

            dis = {begin: 0}

            queue = deque([begin])

            while queue:

                cur = queue.popleft()

                for next_word in self._get_next_words(cur, maps):

                    # 注意下一个词需要未被dis记录

                    # 避免构建循环路径

                    if next_word not in dis:

                        dis[next_word] = dis[cur] + 1

                        queue.append(next_word)

            return dis

        def _get_next_words(self, word, maps):

            """寻找下一个可能的词,其必须在字典中"""

            next_words = []

            for i in range(len(word)):

                next_key = word[:i] + '%' + word[i + 1:]

                for next_word in maps.get(next_key, []):

                    next_words.append(next_word)

            return next_words

    相关文章

      网友评论

          本文标题:LintCode 121. 单词接龙 II

          本文链接:https://www.haomeiwen.com/subject/pgdkrktx.html