📅  最后修改于: 2023-12-03 15:09:21.055000             🧑  作者: Mango
字梯(Word Ladder)是一个单词接龙游戏,从一个单词转化为另一个单词,每次转化只能改变一个字母,且每次转化得到的中间单词都必须为英文单词。
在这个问题中,我们需要找到从起始单词到目标单词路径最短的单词接龙序列。本题的目的是使用双向 BFS 算法优化单向 BFS。
双向 BFS 算法是指从起点和终点同时开始搜索,分别向中间前进,直到两个搜索集合相遇。相遇的位置即为最短路径。
相比于单向 BFS 算法,双向 BFS 可以减少搜索的时间和空间复杂度,尤其是在目标状态不清楚或是搜索空间较大的情况下。
以下是双向 BFS 算法的基本流程:
定义起点集合 begin_set
和终点集合 end_set
,起点集合中只包含起始单词,终点集合中只包含目标单词。
定义两个标记 begin_visited
和 end_visited
,表示起点集合和终点集合中的单词是否已被访问过。
定义一个 set 类型的 word_set
,表示单词词典,从中查找字典中是否存在每个中间单词。
定义一个变量 step
,表示起点和终点相遇时所需的最少步数,初值为 0。
循环搜索,当起点集合不为空时:
begin_set
和 end_set
中元素个数,选择小的那个集合开始搜索。word
,对于当前单词中的每个字符,将其分别替换成 26 个字母中的一个,生成一个新单词 new_word
。new_word
是否在 word_set
中,并且没有被访问过。如果是,则将其加入队列,并将其标记为已访问。end_set
中是否出现了已访问过的单词。出现则结束搜索。否则,将 begin_set
替换为新的搜索结果,step
加 1。返回 step
。
以下是双向 BFS 算法的 Python 代码实现:
def ladderLength(beginWord: str, endWord: str, wordList: List[str]) -> int:
if endWord not in wordList:
return 0
begin_set, end_set = {beginWord}, {endWord}
begin_visited, end_visited = {beginWord}, {endWord}
word_set = set(wordList)
step = 0
while begin_set:
if len(begin_set) > len(end_set):
begin_set, end_set = end_set, begin_set
begin_visited, end_visited = end_visited, begin_visited
next_set = set()
for word in begin_set:
for i in range(len(word)):
for c in 'abcdefghijklmnopqrstuvwxyz':
new_word = word[:i] + c + word[i + 1:]
if new_word in word_set:
if new_word in end_visited:
return step + 2
if new_word not in begin_visited:
next_set.add(new_word)
begin_visited.add(new_word)
begin_set = next_set
step += 1
return 0
双向 BFS 可以大大地提高搜索效率,尤其是在搜索空间较大的问题中。在字梯问题中,用双向 BFS 搜索的时间复杂度是单向 BFS 的一半,因为两个搜索集合相当于将搜索空间分别缩小了一半。同时,双向 BFS 在搜索过程中需要一定的额外空间开销,但是相比于单向 BFS 而言,这个额外开销是很小的。
需要注意的是,在字梯问题中,每次只能改变一个字符,因此可以将每个单词看作一个节点,将可以到达的单词看作一个节点的邻居。这样,问题就被转化为了一张无向图的最短路径问题。