LeetCode #127 单词接龙 BFS 双向BFS

LeetCode #127 单词接龙

题目描述

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

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

说明:

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

示例 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" 不在字典中,所以无法进行转换。
方法一:BFS
# BFS标准套路
for 找head
    while queue:
        for 找邻居
            if 没有重复:处理,标记,入队

在广搜时需要访问单词的所有邻接点,可以使用一个列表字典来保存通用状态的所有匹配单词。如 dog 有三个通用状态:*ogd*gdo**og 这个状态就可以匹配 aogbog 等单词,这样以 *og 为键,匹配到的单词列表为值,就可以得到 dog 这个单词的所有邻居

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        if not endWord in wordList:
            return 0
       	# defaultdict可以在不存在key的时候直接创建这个key
        n, dic = len(beginWord), collections.defaultdict(list)
        # 将所有单词的所有通用状态能匹配到的单词记录下来
        for word in wordList:
            for i in range(n):
                dic[word[:i] + "*" + word[i+1:]].append(word)

        queue = []
        queue.append((beginWord, 1))
        visited = set()
        visited.add(beginWord)
        while queue:
            word, step = queue.pop(0)
            for i in range(n):
                for neightbour in dic[word[:i] + "*" + word[i+1:]]:
                    if neightbour ==endWord:
                        return step + 1
                    if not neightbour in visited:
                        visited.add(neightbour)
                        queue.append((neightbour, step + 1))
        return 0
  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn) m m m 为单词长度, n n n 为单词数量
  • 空间复杂度: O ( m ∗ n ) O(m*n) O(mn)
方法二:双向BFS

思路和BFS基本上一样,就是要从两头一起开始,因为一个单词被访问时的步长就等于从某一头开始变换到这个单词需要的最短步长,所以当从另一头开始的访问列表中出现了这个单词,就可以把从当前的步长加上从另一头访问这个单词的步长,队列退出条件就变成了一个单词同时在两边的访问队列都出现了

class Solution:
    def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
        if not endWord in wordList:
            return 0
        n, dic = len(beginWord), collections.defaultdict(list)
        for word in wordList:
            for i in range(n):
                dic[word[:i] + "*" + word[i+1:]].append(word)

        beginQueue = []
        beginQueue.append((beginWord, 1))
        # 记录下变换到每个单词的最短步长
        beginVisited = collections.defaultdict()
        beginVisited[beginWord] = 1
        
        endQueue = []
        endQueue.append((endWord, 1))
        # 记录下变换到每个单词的最短步长
        endVisited = collections.defaultdict()
        endVisited[endWord] = 1
        
        while beginQueue and endQueue:
            word, step = beginQueue.pop(0)
            for i in range(n):
                for neightbour in dic[word[:i] + "*" + word[i+1:]]:
                    if neightbour in endVisited:
                        return step + endVisited[neightbour]
                    if not neightbour in beginVisited:
                        beginVisited[neightbour] = step + 1
                        beginQueue.append((neightbour, step + 1))

            word, step = endQueue.pop(0)
            for i in range(n):
                for neightbour in dic[word[:i] + "*" + word[i+1:]]:
                    if neightbour in beginVisited:
                        return step + beginVisited[neightbour]
                    if not neightbour in endVisited:
                        endVisited[neightbour] = step + 1
                        endQueue.append((neightbour, step + 1))
        return 0       
  • 时间复杂度: O ( m ∗ n ) O(m*n) O(mn):和单向BFS一样,但是时间会缩短一半,因为两个搜索会在中间某处相遇
  • 空间复杂度: O ( m ∗ n ) O(m*n) O(mn)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值