127. Word Ladder¶
Edited by Charles
Hard · Python · Graph
Problem
Read the original problem on LeetCode.
The official page contains the problem statement, examples, and constraints.
Explanation, examples & other approaches
Core idea
This problem can be viewed as a shortest path problem in an unweighted graph.
Original study notes follow, including intermediate snippets and earlier attempts.
Idea¶
This problem can be viewed as a shortest path problem in an unweighted graph.
We can think of:
Two words are connected by an edge if they differ by exactly one character.
For example:
Since every transformation has the same cost (1 step), we should use BFS to find the shortest transformation sequence.
BFS is suitable because it explores the graph level by level, so the first time we reach
endWord, we have found the shortest path.
Graph Representation¶
We do not need to explicitly construct the entire graph.
Instead, for each current word, we generate all possible neighboring words by replacing each character with a-z.
For example:
For the first position:
For the second position:
For the third position:
If a generated word exists in wordList, then it is a valid neighbor.
Why Use a Set?¶
Convert wordList into a set:
We frequently need to check:
Using a set gives approximately:
lookup time.
Also, once a word is visited, we remove it from the set:
This prevents the same word from being visited multiple times.
Therefore, wordSet also works as our visited structure.
BFS¶
Initialize the queue with:
Each element contains:
where step represents the number of words in the current transformation sequence.
For example:
means the current sequence contains only:
BFS Process¶
For each word removed from the queue:
If:
we return:
Otherwise, generate all possible words that differ by one character.
For every valid unvisited word:
remove it from wordSet:
and add it to the queue:
Why BFS Instead of DFS?¶
Consider:
There may be many different transformation paths.
DFS may explore a very long path before finding the destination.
BFS explores by distance:
Therefore, the first time BFS reaches endWord, that path must be the shortest transformation sequence.
A useful rule is:
Hand Simulation¶
Consider:
Initially:
Level 1¶
Pop:
Generate its valid neighbor:
Queue becomes:
Level 2¶
Pop:
Valid unvisited neighbors:
Queue:
Level 3¶
From dot:
From lot:
Queue:
Level 4¶
From dog:
So:
Eventually we pop:
Since:
return:
The shortest transformation sequence is:
which contains 5 words.
Important Detail: Why Is the Answer 5 Instead of 4?¶
There are four transformations:
However, the problem asks for the number of words in the transformation sequence, not the number of edges.
Therefore:
The answer is:
This is why we initialize:
instead of starting with 0.
Important Detail: endWord Must Exist¶
If:
there is no valid transformation sequence because every transformed word must exist in wordList.
Therefore:
Complexity Analysis¶
Let:
For each word, we try:
Therefore, ignoring the cost of Python string construction, the main search work is approximately:
With string construction included, it can be viewed as:
since creating each candidate string costs O(L).
Space Complexity:
for the set and BFS queue, aside from storage for generated strings.
Summary¶
1. Treat every word as a vertex.
2. Two words have an edge if they differ by one character.
3. The problem becomes an unweighted shortest-path problem.
4. Use BFS.
5. Generate neighbors by replacing each character with a-z.
6. Use a set for fast lookup.
7. Remove words from the set once visited.
8. Store (word, step) in the queue.
9. Return step when endWord is reached.
The most important idea is:
Word Ladder is a hidden unweighted graph shortest-path problem, so BFS is the natural solution.
Study record
| Field | Value |
|---|---|
| Attempts | 1 |
| Mastery | ❚ |
| The Latest Attempt | August 20, 2026 |
Python solution¶
from collections import deque
class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
wordSet = set(wordList)
if endWord not in wordSet:
return 0
queue = deque([(beginWord, 1)])
while queue:
word, step = queue.popleft()
if word == endWord:
return step
for i in range(len(word)):
for char in string.ascii_lowercase:
newWord = word[: i] + char + word[i + 1:]
if newWord in wordSet:
wordSet.remove(newWord)
queue.append((newWord, step + 1))
return 0