Word Ladder
Given beginWord, endWord, and a wordList, find the length of the shortest transformation sequence from beginWord to endWord, changing only one letter at a time, where every intermediate word must exist in wordList. Return 0 if no such sequence exists. Treat every word as a node and every one-letter change to another word in the list as an edge . Then breadth-first search from beginWord finds the shortest chain, because it explores one letter-change away before any two letter-changes away.
Constraints
- 1 ≤ beginWord.length ≤ 10
- endWord.length == beginWord.length
- 1 ≤ wordList.length ≤ 5000
- wordListi.length == beginWord.length
- beginWord, endWord, and wordListi consist of lowercase English letters
- beginWord != endWord
- All the words in wordList are unique
Example
beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]5Explanation One shortest transformation is hit -> hot -> dot -> dog -> cog, a sequence of 5 words.
In plain terms
- Node
- One item in the graph being searched — here, a single word.
- Edge
- A connection between two nodes — here, two words that differ by exactly one letter.
One cell per word — each shows how long the chain is when BFS first reaches it
Start the queue with hit, sequence length 1. Every other word is still unreached.
What happens in this step
wordSet = {hot, dot, dog, lot, log, cog}
queue = [(hit, len1)] visited = {hit}
endWord "cog" is in wordSet, so a path is possible.Steps to visualize
- The row has one slot for each of the seven words in play: beginWord "hit" plus the six words in wordList.
- A slot shows — until the search reaches that word; then it shows the length of the chain that got there.
- If endWord is not in wordList, there is no way to reach it — return 0 immediately.
- Start a queue with beginWord, sequence length 1.
- Dequeue a word; for every position, try swapping in each other letter of the alphabet.
- If the result is in wordList and has not been visited, enqueue it at length + 1.
- The first time endWord is dequeued, its length is the shortest sequence.
Walk through the code
Same walkthrough, now with the code. Press Next to move one step and watch which lines run.
Start the queue with hit, sequence length 1. Every other word is still unreached.
What happens in this step
wordSet = {hot, dot, dog, lot, log, cog}
queue = [(hit, len1)] visited = {hit}
endWord "cog" is in wordSet, so a path is possible.Solution
function ladderLength(beginWord, endWord, wordList) {
const wordSet = new Set(wordList);
if (!wordSet.has(endWord)) return 0;
const alphabet = 'abcdefghijklmnopqrstuvwxyz';
const queue = [[beginWord, 1]];
const visited = new Set([beginWord]);
while (queue.length > 0) {
const [word, steps] = queue.shift();
if (word === endWord) return steps;
for (let i = 0; i < word.length; i++) {
for (const ch of alphabet) {
if (ch === word[i]) continue;
const candidate = word.slice(0, i) + ch + word.slice(i + 1);
if (wordSet.has(candidate) && !visited.has(candidate)) {
visited.add(candidate);
queue.push([candidate, steps + 1]);
}
}
}
}
return 0;
}- Time
- O(n * L^2 * 26)
- Space
- O(n * L)
Test cases
| Input | Expected | Covers |
|---|---|---|
beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] | 5 | example from the docstring |
beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"] | 0 | endWord is missing from wordList, so no path can exist |
beginWord = "hot", endWord = "dot", wordList = ["dot"] | 2 | a one-letter change reaches the target directly |
beginWord = "a", endWord = "c", wordList = ["a","b","c"] | 2 | a distractor word (b) exists but the direct change is shorter |
beginWord = "hot", endWord = "dog", wordList = ["hot","dog"] | 0 | the words differ in more than one letter with no intermediate bridge |
beginWord = "cat", endWord = "cot", wordList = ["cot","dot","cat"] | 2 | multiple candidate words, but only one is a valid one-letter change |
beginWord = "hit", endWord = "dot", wordList = ["hot","dot"] | 3 | a short chain requiring exactly one intermediate word |