127.单词接龙

127.单词接龙

难度:中等

标签:双向BFS

题目描述

给定两个单词(beginWordendWord)和一个字典,找到从 beginWordendWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWordendWord 是非空的,且二者不相同。

示例 1:

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

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
     返回它的长度 5。

示例 2:

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

输出: 0

解释: endWord "cog" 不在字典中,所以无法进行转换。

题解

对于本题来说,从beginWordendWord与从endWordbeginWord最终得到的结果是一样的,可以分别从两端构造一个树,树的结点是转换过程中的中间节点,然后利用BFS进行搜索,找到最短路径长度,也就是树的最小高度。对于BFS来说,复杂度与树的每一层的结点数量相关,为了加速查找,可以采取两端搜索的方法来进行优化,也就是说一端从beginWordendWord进行查找,另一端从endWordendWord进行查找,每次BFS遍历中间结点个数少的那一端。

举个例子:

  • 假设从beginWord转换为endWord,存在于字典中的,(第一个)中间结果有30个。
  • 而,从endWord转换为beginWord,存在于字典中的,(第一个)中间结果只有2个。
  • 那么,很显然。从endWord开始会更快。所以,每次都从个数少的那块开始替换一位。

代码

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        if endWord not in wordList:
            return 0
        
        l = len(endWord)
        
            
        ws = set(wordList)
        
        head = {beginWord}
        tail = {endWord}
        tmp = list('abcdefghijklmnopqrstuvwxyz')
        res = 1
        while head:
            if len(head) > len(tail):
                head, tail = tail, head
            
            q = set()
            for cur in head:
                for i in range(l):
                    for j in tmp:
                        word = cur[:i] + j + cur[i+1:]

                        if word in tail:
                            return res + 1

                        if word in ws:
                            q.add(word)
                            ws.remove(word)
            head = q
            res += 1
                
        return 0

总结

对于一个BFS问题来说,一般都具备几个要素:

  1. 需要有边界条件:边界条件可能为迷宫的墙壁和边缘,也可能为题目中给出的不可用的数据

  2. 有已访问数组:当前位置未被访问是能够入队列的必要条件

  3. 可能有前驱节点:用于需要输出路径时添加

  4. 需要队列来存储当前层的节点

双向BFS核心技巧:使用两个队列进行BFS,每次只遍历队列较短的一侧

你可能感兴趣的:(LeetCode笔记,算法,leetcode,python,bfs)