Skip to main content

126.单词接龙 II

标签: breadth-first-search, backtracking

难度: Hard

通过率: 27.12%

原题链接: https://leetcode.com/problems/word-ladder-ii/description/

题目描述

给定两个单词,beginWord 和 endWord,再给一个字典 wordList,返回从 beginWord 变换到 endWord 的所有最短转换序列。每次变换只能改变一个字母,每次变换后的中间单词都必须在字典 wordList 里。

如果不存在这样的序列,返回空列表。

解题思路

解决这个问题可以通过广度优先搜索(BFS)来寻找最短路径,再结合回溯法来构造所有的路径。

  • 步骤1: 广度优先搜索

    • 先使用BFS从起始单词 beginWord 开始查找所有可能的变换路径,一直到遇到目标单词 endWord
    • 在遍历过程中,我们需要建立一个映射关系 word -> 前驱单词列表,用于记录在某个层级上某个单词是通过哪些单词变换而来的。
    • 为了优化,我们可以从两端(beginWordendWord)同时进行 BFS,这样可以减少遍历的层级。
  • 步骤2: 回溯构造路径

    • 在得到所有的前驱单词信息后,使用深度优先搜索(DFS)或回溯,结合从 endWordbeginWord 回溯来构造所有的最短路径序列。
  • 注意点:

    • 我们需要在 BFS 的过程中维护一个 level 的信息,以确保我们可以找到最短路径。
    • 可以通过在 BFS 中访问单词时,标记该单词已经访问过,以避免重复访问。
  • 边界情况:

    • 如果 endWord 不在 wordList 中,直接返回空列表。

代码实现

from collections import defaultdict, deque

def findLadders(beginWord, endWord, wordList):
wordSet = set(wordList)
if endWord not in wordSet:
return []

# 使用双向BFS以加速搜索
front, back = {beginWord}, {endWord}
tree, is_found = defaultdict(set), False
wordSet.discard(beginWord)

while front and not is_found:
next_front = set()

for word in front:
for i in range(len(word)):
for c in 'abcdefghijklmnopqrstuvwxyz':
neigh = word[:i] + c + word[i+1:]
if neigh in back:
is_found = True
tree[neigh].add(word)
if neigh in wordSet:
tree[neigh].add(word)
next_front.add(neigh)

wordSet -= next_front
front = next_front if len(next_front) < len(back) else back
back = back if len(next_front) < len(back) else front

def backtrack(word):
if word == beginWord:
return [[beginWord]]
return [[word] + path for w in tree[word] for path in backtrack(w)]

return backtrack(endWord)

复杂度分析

时间复杂度:O(N×M2)O(N \times M^2),其中 NN 是字典中单词的数量,MM 是单词的长度。在最坏的情况下,我们需要将每个单词的每个字符替换为其他 25 个字母,总共有 N×M×26N \times M \times 26 次操作。 空间复杂度:O(N×M)O(N \times M),用于存储字典、队列和树。