1. Problem Statement
Given two words, beginWord and endWord, and a dictionary wordList, return all the shortest transformation sequences from beginWord to endWord.
Each sequence should be a list of words [beginWord, s1, s2, ..., sk] where every adjacent pair differs by one letter.
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: [["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
2. Approach: BFS (Distances) + DFS (Backtracking)
The core challenge is finding all shortest paths, not just one.
- BFS for Distance: Perform a BFS starting from
beginWordto calculate the shortest distance from the source to every word in the dictionary. Store this in aMap<String, Integer> distanceMap. - Backtracking for Paths: Start from
endWord(orbeginWord) and use thedistanceMapto guide your search.- If you are at word
Wwith distanceD, only move to neighbors whose distance isD - 1. - This ensures every path you find is guaranteed to be a shortest path.
- If you are at word
3. Java Implementation
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
List<List<String>> res = new ArrayList<>();
Set<String> dict = new HashSet<>(wordList);
if (!dict.contains(endWord)) return res;
Map<String, Integer> distances = new HashMap<>();
Map<String, List<String>> adj = new HashMap<>();
// 1. BFS to find minimum distances and build adjacency graph
bfs(beginWord, endWord, dict, distances, adj);
// 2. DFS to reconstruct paths
List<String> path = new ArrayList<>();
path.add(beginWord);
dfs(beginWord, endWord, distances, adj, path, res);
return res;
}
private void bfs(String start, String end, Set<String> dict,
Map<String, Integer> dist, Map<String, List<String>> adj) {
Queue<String> q = new LinkedList<>();
q.offer(start);
dist.put(start, 0);
for (String s : dict) adj.put(s, new ArrayList<>());
adj.put(start, new ArrayList<>());
boolean found = false;
while (!q.isEmpty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
String curr = q.poll();
int d = dist.get(curr);
List<String> neighbors = getNeighbors(curr, dict);
for (String n : neighbors) {
adj.get(curr).add(n);
if (!dist.containsKey(n)) {
dist.put(n, d + 1);
if (n.equals(end)) found = true;
else q.offer(n);
}
}
}
if (found) break;
}
}
4. 5-Minute "Video-Style" Walkthrough
- The "Aha!" Moment: Word Ladder I is about finding a number. Word Ladder II is about Tracing the Map. You cannot find the paths in the BFS pass alone without consuming massive memory.
- The Guide: The
distanceMapis your GPS. It tells you exactly which way to go at every crossroads to stay on the shortest path. - The Reverse: Why backtrack? Because it prunes all dead ends. Every step you take using the
distanceMapis guaranteed to lead closer to the destination.
5. Interview Discussion
- Interviewer: "Why is this harder than Word Ladder I?"
- You: "In I, we just return the level. In II, we must explore all branches of the same level. If 'hot' and 'dot' both lead to 'dog' in the same number of steps, we need to record both."
- Interviewer: "Complexity?"
- You: "The time complexity is dominated by the number of possible shortest paths, which can be exponential in the worst case. The BFS part is $O(N \times L^2)$."