LeetCode Word Ladder II

LeetCode解题之Word Ladder II


原题

给定一个起始字符串和一个目标字符串,现在将起始字符串按照特定的变换规则转换为目标字符串,求所有转换次数最少的转换过程。转换规则为每次只能改变字符串中的一个字符,且每次转换后的字符串都要在给定的字符串集合中。

注意点:

  • 所有给出的字符串的长度都相等
  • 所有的字符都为小写字母

例子:

输入: beginWord = “hit”, endWord = “cog”, wordList = [“hot”,”dot”,”dog”,”lot”,”log”]

输出:

  [
    ["hit","hot","dot","dog","cog"],
    ["hit","hot","lot","log","cog"]
  ]

解题思路

整体思想与Word Ladder一样,都是采用DFS的方法。不过要做出以下的变化:

  1. 在Word Ladder中,广度优先遍历是从上层到下层一层层遍历下去的,还是以下面的图为例,树结构可能是中间宽两头窄的情况。而一个节点转换为下层节点时,要依次将它字符串中的每个字符用其他字母替换后与给定字符串集合进行比较。如果树某一层的节点非常多,那么这个尝试转换的操作开销就很大。还需要明确的一点是,题目中的转换是可逆的,A可以转换为B,那么B也可以转换为A,且A和B都能转换为它们转换过程的某一个状态C。综上所述,我们可以从起始字符串和目标字符串同时进行转换,哪一端的节点数目少,我们就选这些节点继续进行转换,直到它们汇合到同一个节点或者转换终止(也就是下一层没有节点)。代码中由变量is_forward来表示从哪一端转换。
  2. 现在是要求所有最少转换次数的转换方法,所以要将所有的转换可能都找出来。如图中bit和him转换为bim的转换关系我们都要找出来。
  3. 我们还需要记录转换的路径,我们将从上一层到下一层的转换关系记录下来,等到确定能够转换成功了,再通过深度优先遍历的方法将转换路径组装起来。

word ladder

注:图中的有些单词没有意义,只是单纯为了举例子,图对应的起始字符串为hit,给定的字符串集合为{“hot”,”hat”,”bit”,”him”,”bot”,”bim”}

AC源码

class Solution(object):
    def findLadders(self, beginWord, endWord, wordlist):
        """
        :type beginWord: str
        :type endWord: str
        :type wordlist: Set[str]
        :rtype: List[List[int]]
        """

        def bfs(front_level, end_level, is_forward, word_set, path_dic):
            if len(front_level) == 0:
                return False
            if len(front_level) > len(end_level):
                return bfs(end_level, front_level, not is_forward, word_set, path_dic)
            for word in (front_level | end_level):
                word_set.discard(word)
            next_level = set()
            done = False
            while front_level:
                word = front_level.pop()
                for c in 'abcdefghijklmnopqrstuvwxyz':
                    for i in range(len(word)):
                        new_word = word[:i] + c + word[i + 1:]
                        if new_word in end_level:
                            done = True
                            add_path(word, new_word, is_forward, path_dic)
                        else:
                            if new_word in word_set:
                                next_level.add(new_word)
                                add_path(word, new_word, is_forward, path_dic)
            return done or bfs(next_level, end_level, is_forward, word_set, path_dic)

        def add_path(word, new_word, is_forward, path_dic):
            if is_forward:
                path_dic[word] = path_dic.get(word, []) + [new_word]
            else:
                path_dic[new_word] = path_dic.get(new_word, []) + [word]

        def construct_path(word, end_word, path_dic, path, paths):
            if word == end_word:
                paths.append(path)
                return
            if word in path_dic:
                for item in path_dic[word]:
                    construct_path(item, end_word, path_dic, path + [item], paths)

        front_level, end_level = {beginWord}, {endWord}
        path_dic = {}
        bfs(front_level, end_level, True, wordlist, path_dic)
        path, paths = [beginWord], []
        construct_path(beginWord, endWord, path_dic, path, paths)
        return paths


if __name__ == "__main__":
    assert Solution().findLadders("hit", "cog", {"hot", "dot", "dog", "lot", "log"}) == [
        ["hit", "hot", "dot", "dog", "cog"],
        ["hit", "hot", "lot", "log", "cog"]
    ]

欢迎查看我的Github (https://github.com/gavinfish/LeetCode-Python) 来获得相关源码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值