#127 Word Ladder
frequently reported atLinkedInAmazonByteDance / TikTokAppleMetaMicrosoft
the problem
In plain words
Transform beginWord into endWord by changing one letter at a time; every intermediate word must be in wordList. Return the number of words in the shortest sequence (including both ends), or 0 if impossible.
in beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
out 5
hit → hot → dot → dog → cog.
in beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
out 0
"cog" is not in the list.
- 1 ≤ word length ≤ 10
- 1 ≤ wordList.length ≤ 5000
- Lowercase letters; all words the same length and unique; beginWord ≠ endWord
your turn
Try it before you peek
Read the examples, say the brute force out loud, then write code: here or on LeetCode ↗. Stuck for 20 minutes? Open one hint at a time.
Solve it in the browser
LeetCode-style: complete the class. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
Solutions are hidden so you can try first. Even 20 minutes of real effort makes the answer stick far better than reading it.
Marking the problem solved, or opening every hint, also shows it.
the aha
Key insight
patternBFS shortest path (unweighted)
Words are vertices; two words are adjacent if they differ in one letter. "Shortest sequence" in an unweighted graph = BFS. Generate neighbours by trying 26 letters per position instead of comparing all pairs.
solutions
From brute force to optimal
Compare every pair of words to create edges, then BFS.
- For all i < j, connect words differing in exactly one position.
- BFS from beginWord; dist counts words.
N² pairs, each compared in O(L).
Up to N² edges in the adjacency lists.
class Solution { /** Build the graph explicitly by comparing every pair of words, then BFS. */ public int ladderLength(String beginWord, String endWord, List<String> wordList) { List<String> words = new ArrayList<>(wordList); if (!words.contains(endWord)) return 0; if (!words.contains(beginWord)) words.add(beginWord); int n = words.size(); List<List<Integer>> adj = new ArrayList<>(); for (int i = 0; i < n; i++) adj.add(new ArrayList<>()); for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) if (oneApart(words.get(i), words.get(j))) { adj.get(i).add(j); adj.get(j).add(i); } int[] dist = new int[n]; // words in the sequence so far; 0 = unseen int start = words.indexOf(beginWord), target = words.indexOf(endWord); Deque<Integer> queue = new ArrayDeque<>(List.of(start)); dist[start] = 1; while (!queue.isEmpty()) { int u = queue.poll(); if (u == target) return dist[u]; for (int v : adj.get(u)) if (dist[v] == 0) { dist[v] = dist[u] + 1; queue.offer(v); } } return 0; } private boolean oneApart(String a, String b) { int diff = 0; for (int i = 0; i < a.length() && diff < 2; i++) if (a.charAt(i) != b.charAt(i)) diff++; return diff == 1; }}From each word, try every position × 26 letters; keep candidates still in the unvisited set.
- unvisited = HashSet(wordList); return 0 if endWord is missing.
- BFS level by level;
lengthcounts words. - For each word: for each position, for each letter → if in unvisited: endWord? return length+1; else remove and enqueue.
Each of N words is expanded once: L positions × 26 letters, each building and hashing an L-char string.
The set and the queue store words of length L.
class Solution { /** Don't build the graph: generate neighbours by trying all 26 letters at each position. */ public int ladderLength(String beginWord, String endWord, List<String> wordList) { Set<String> unvisited = new HashSet<>(wordList); if (!unvisited.contains(endWord)) return 0; Deque<String> queue = new ArrayDeque<>(List.of(beginWord)); unvisited.remove(beginWord); for (int length = 1; !queue.isEmpty(); length++) { for (int size = queue.size(); size > 0; size--) { // one level = one more word char[] w = queue.poll().toCharArray(); for (int i = 0; i < w.length; i++) { char original = w[i]; for (char ch = 'a'; ch <= 'z'; ch++) { if (ch == original) continue; w[i] = ch; String next = new String(w); if (!unvisited.contains(next)) continue; if (next.equals(endWord)) return length + 1; unvisited.remove(next); // removing = marking visited queue.offer(next); } w[i] = original; // undo before trying the next position } } } return 0; }}Dry run
Search from both ends and always expand the smaller frontier; stop when they meet.
- front = {begin}, back = {end}.
- Expand the smaller set by one level.
- If a candidate is in the other set → the searches met.
Same worst case, but each side only needs about half the depth — far fewer words explored in practice.
Two frontier sets and the dictionary.
class Solution { /** Grow two frontiers (from begin and from end); always expand the smaller one. */ public int ladderLength(String beginWord, String endWord, List<String> wordList) { Set<String> dict = new HashSet<>(wordList); if (!dict.contains(endWord)) return 0; Set<String> front = new HashSet<>(Set.of(beginWord)), back = new HashSet<>(Set.of(endWord)); dict.remove(beginWord); dict.remove(endWord); for (int length = 2; !front.isEmpty() && !back.isEmpty(); length++) { if (front.size() > back.size()) { // expand the cheaper side Set<String> t = front; front = back; back = t; } Set<String> next = new HashSet<>(); for (String word : front) { char[] w = word.toCharArray(); for (int i = 0; i < w.length; i++) { char original = w[i]; for (char ch = 'a'; ch <= 'z'; ch++) { w[i] = ch; String cand = new String(w); if (back.contains(cand)) return length; // the two searches met if (dict.remove(cand)) next.add(cand); } w[i] = original; } } front = next; } return 0; }}in the room
How to say it in the interview
talk track
- Say: "It's shortest path in an unweighted implicit graph → BFS."
- Point out the cost trade-off: comparing pairs is N²·L; generating 26·L candidates per word wins when N is large.
- Removing a word from the set when you enqueue it is the visited mark.
traps
- Returning edges instead of words (off by one).
- Not checking that endWord is in the list first.
- Forgetting to restore
w[i]before trying the next position.
what they ask next
Follow-ups
Word Ladder II (LC 126): return all shortest sequences?
BFS to record each word's parents level by level (only from the previous level), then DFS/backtrack from endWord to rebuild paths.
before you submit
Edge cases to test
- endWord not in wordList → 0 straight away.
- beginWord need not be in the list; if it is, remove it so it isn't revisited.
- endWord is one change away → 2 (the answer counts words, not changes).
- No ladder exists → the queue empties and the answer is 0.
practise next
Similar problems
- #433Minimum Genetic MutationMediumin Graphs
- #909Snakes and LaddersMediumin Graphs
- #1091Shortest Path in Binary MatrixMediumin Graphs