LeetCode 126:单词接龙 II
LeetCode 126:单词接龙 II

问题本质与核心挑战
需找到 所有从 beginWord 到 endWord 的最短转换序列,要求:
- 相邻单词仅差一个字母;
- 中间单词必须在
wordList中。
核心挑战:
- 如何高效找到最短路径(BFS 天然适合,但需记录路径);
- 如何收集所有最短路径(需回溯前驱节点);
- 如何避免重复搜索(通过层级控制和距离记录)。
核心思路:BFS 找层级 + 回溯找路径
1. 预处理:构建模式映射(邻接表优化)
将每个单词转换为 通配符模式(如 hot → *ot、h*t、ho*),同一模式的单词互为相邻(差一个字母)。通过哈希表 patternMap 存储模式→单词列表,快速查找相邻单词。
2. BFS 遍历:记录距离和前驱
- 距离
distance:记录每个单词到beginWord的最短步数(层级); - 前驱
predecessors:记录每个单词的前驱节点(用于回溯路径); - 层级控制:BFS 保证层级递增,一旦找到
endWord,后续层级更长,可提前终止。
3. 回溯生成路径
从 endWord 出发,递归回溯所有前驱节点,直到 beginWord,反转路径后收集结果。
算法步骤详解(以示例 1 为例:beginWord="hit", endWord="cog", wordList=["hot","dot","dog","lot","log","cog"])
步骤 1:预处理与边界检查
- 将
wordList转成Set(快速判断存在性); - 若
endWord不在wordSet中,直接返回空列表(如示例 2); - 构建
patternMap:
例如,Map<String, List<String>> patternMap = new HashMap<>(); for (String word : wordSet) {for (int i = 0; i < word.length(); i++) {String pattern = word.substring(0, i) + "*" + word.substring(i+1);patternMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word);} }hot生成模式*ot、h*t、ho*,对应单词dot、lot、hot等。
步骤 2:BFS 遍历,记录距离和前驱
- 初始化:队列加入
beginWord,distance记录beginWord层级为1; - 遍历队列:
- 对当前单词
current,生成所有模式,找到相邻单词neighbor; - 若
neighbor未访问:记录距离(currentLevel+1)、前驱,加入队列; - 若
neighbor已访问且距离等于currentLevel+1(同一层级的不同路径):添加前驱; - 若遇到
endWord,记录当前层级shortestLevel,处理完当前层级后终止 BFS。
- 对当前单词
示例 1 的 BFS 过程(关键步骤):
| 层级 | 当前单词 | 相邻单词 | 距离更新 | 前驱记录 |
|---|---|---|---|---|
| 1 | hit | hot | hot→2 | hot: [hit] |
| 2 | hot | dot、lot | dot→3, lot→3 | dot: [hot], lot: [hot] |
| 3 | dot | dog | dog→4 | dog: [dot] |
| 3 | lot | log | log→4 | log: [lot] |
| 4 | dog | cog | cog→5 | cog: [dog] |
| 4 | log | cog | cog→5(补充前驱) | cog: [dog, log] |
步骤 3:回溯生成所有最短路径
从 endWord 出发,递归遍历前驱节点,直到 beginWord,反转路径后加入结果:
private void backtrack(String current, String beginWord, Map<String, List<String>> predecessors, List<String> path, List<List<String>> result) {if (current.equals(beginWord)) {List<String> reversed = new ArrayList<>(path);Collections.reverse(reversed);result.add(reversed);return;}for (String pre : predecessors.getOrDefault(current, new ArrayList<>())) {path.add(pre);backtrack(pre, beginWord, predecessors, path, result);path.remove(path.size() - 1);}
}
示例 1 的回溯过程:
cog的前驱是dog和log:dog→dot→hot→hit→ 路径[hit, hot, dot, dog, cog];log→lot→hot→hit→ 路径[hit, hot, lot, log, cog]。
完整代码(Java)
import java.util.*;class Solution {public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {List<List<String>> result = new ArrayList<>();Set<String> wordSet = new HashSet<>(wordList);// 边界:endWord不在字典中if (!wordSet.contains(endWord)) {return result;}// 构建模式映射:通配符模式→单词列表Map<String, List<String>> patternMap = new HashMap<>();for (String word : wordSet) {for (int i = 0; i < word.length(); i++) {String pattern = word.substring(0, i) + "*" + word.substring(i + 1);patternMap.computeIfAbsent(pattern, k -> new ArrayList<>()).add(word);}}// BFS初始化:队列、距离、前驱、最短层级Queue<String> queue = new LinkedList<>();queue.offer(beginWord);Map<String, Integer> distance = new HashMap<>();distance.put(beginWord, 1);Map<String, List<String>> predecessors = new HashMap<>();int shortestLevel = -1;while (!queue.isEmpty()) {if (shortestLevel != -1) break; // 已找到最短路径,终止后续层级int size = queue.size();for (int i = 0; i < size; i++) {String current = queue.poll();int currentLevel = distance.get(current);// 找到endWord,记录最短层级if (current.equals(endWord)) {shortestLevel = currentLevel;}// 生成所有相邻单词(通过模式匹配)for (int j = 0; j < current.length(); j++) {String pattern = current.substring(0, j) + "*" + current.substring(j + 1);List<String> neighbors = patternMap.getOrDefault(pattern, new ArrayList<>());for (String neighbor : neighbors) {if (!distance.containsKey(neighbor)) {// 未访问过,记录距离和前驱distance.put(neighbor, currentLevel + 1);predecessors.computeIfAbsent(neighbor, k -> new ArrayList<>()).add(current);queue.offer(neighbor);} else if (distance.get(neighbor) == currentLevel + 1) {// 同一层级的不同路径,补充前驱predecessors.computeIfAbsent(neighbor, k -> new ArrayList<>()).add(current);}}}}}// 未找到路径if (shortestLevel == -1) {return result;}// 回溯生成所有路径List<String> path = new ArrayList<>();path.add(endWord);backtrack(endWord, beginWord, predecessors, path, result);return result;}// 回溯函数:从endWord递归找前驱,直到beginWord,收集路径private void backtrack(String current, String beginWord, Map<String, List<String>> predecessors, List<String> path, List<List<String>> result) {if (current.equals(beginWord)) {List<String> reversed = new ArrayList<>(path);Collections.reverse(reversed);result.add(reversed);return;}// 遍历所有前驱,递归回溯for (String pre : predecessors.getOrDefault(current, new ArrayList<>())) {path.add(pre);backtrack(pre, beginWord, predecessors, path, result);path.remove(path.size() - 1); // 回溯}}
}
关键逻辑解析
- 模式映射:将单词转换为通配符模式,快速定位相邻单词,时间复杂度从
O(n²)降为O(n×L)(L为单词长度)。 - BFS 层级控制:保证首次到达
endWord时的层级为最短路径,后续层级无需处理。 - 前驱记录:同一层级的不同路径需补充前驱,确保回溯时收集所有可能的最短路径。
- 回溯生成路径:从
endWord反向遍历前驱,通过递归和路径回溯,生成所有符合条件的序列。
该方法结合 BFS 的层级优势 和 回溯的路径收集能力,高效解决了“最短路径全收集”问题,时间复杂度为 O(N×L + P)(N 为单词数,L 为单词长度,P 为最短路径数量),是处理此类问题的经典范式。
