1. Problem Statement
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> ... -> sk such that:
- Every adjacent pair of words differs by a single letter.
- Every
sifor $1 \le i \le k$ is inwordList.
Given two words, beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence, or 0 if no such sequence exists.
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: 5 (hit -> hot -> dot -> dog -> cog)
2. Approach: Breadth-First Search (BFS)
Shortest path in an unweighted graph is always a BFS problem.
- Nodes: Every word in the list.
- Edges: Two words have an edge if they differ by exactly one letter.
- Traversal: Start from
beginWord, explore all neighbors (1-letter diff), then their neighbors, and so on. The first time we hitendWord, the current level is our shortest path.
3. Java Implementation
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
Set<String> set = new HashSet<>(wordList);
if (!set.contains(endWord)) return 0;
Queue<String> queue = new LinkedList<>();
queue.add(beginWord);
int level = 1;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
String curr = queue.poll();
if (curr.equals(endWord)) return level;
// Try changing every character (a to z)
char[] words = curr.toCharArray();
for (int j = 0; j < words.length; j++) {
char originalChar = words[j];
for (char c = 'a'; c <= 'z'; c++) {
if (c == originalChar) continue;
words[j] = c;
String target = String.valueOf(words);
if (set.contains(target)) {
queue.offer(target);
set.remove(target); // Mark as visited
}
}
words[j] = originalChar;
}
}
level++;
}
return 0;
}
4. 5-Minute "Video-Style" Walkthrough
- The "Aha!" Moment: Imagine a massive cloud of words. A "transformation" is like jumping from one word to another. We want the fewest jumps. BFS ensures we explore all 1-jump words before any 2-jump words.
- The Neighbor Search: To find neighbors of "hit", don't compare it to every word in the list ($O(N \times L)$). Instead, change every letter of "hit" ($O(26 \times L)$) and check if that new string is in our set. This is much faster when the dictionary is large.
- The Efficiency: Removing words from the
setafter adding them to the queue is our "visited" logic. It prevents us from jumping in circles.
5. Interview Discussion
- Interviewer: "What is the time complexity?"
- You: "O(N * L^2) where N is the number of words and L is the length. We iterate through N words, and for each, we do L length loops with string generation."
- Interviewer: "Can we optimize this?"
- You: "Yes, with Bidirectional BFS. By starting the search from both
beginWordandendWordand meeting in the middle, we significantly reduce the search space (the exponent of the branching factor is halved)."