Find the shortest chain of one-letter changes from one word to another using BFS with wildcard buckets in O(N·L²). Classic Amazon/Google hard, run live.
The problem
Transform begin into end by changing one letter at a time, where every intermediate word must be in words. Return the number of words in the shortest such sequence (including begin and end), or 0 if impossible.
Examples
Example 1
Input
ladder_length('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log', 'cog'])Expected output
5
Example 2
Input
ladder_length('hit', 'cog', ['hot', 'dot', 'dog', 'lot', 'log'])Expected output
0
+ 3 hidden tests on Submit — no bridge word.
Edge cases to ask about
- end not in the word list
- begin == end
- No path
Hints
0/3How an interviewer scores this
0/9Your code runs in real CPython inside your browser — nothing is sent anywhere. The first run downloads the interpreter (about 6 MB, once). Your code is saved on this device as you type.
Complexity Lab
What does this cost as n grows?
Interviewers score the analysis as much as the code. Commit to an answer first — then check it, and read why.
Pick both to reveal the answer.
From brute force to optimal
The progression an interviewer wants to hear, one step at a time.
| Approach | Time | Space | Idea |
|---|---|---|---|
| Compare every pair of words to build edges | O(N² · L) | O(N²) | |
| BFS + wildcard buckets | O(N · L²) | O(N · L²) | 'h*t' groups hot, hit, hat — neighbours without pairwise comparison. |
| bestBidirectional BFS | O(N · L²) | O(N · L²) | Much smaller frontiers in practice. |
Walkthrough of the optimal approach (try it yourself first)
Unweighted shortest path means BFS. The expensive part is finding neighbours: comparing every pair is O(N²·L). Instead, bucket each word under its L wildcard patterns (hot → *ot, h*t, ho*). Two words are neighbours exactly when they share a bucket.
Mark words seen on enqueue so each is queued once, and clear a bucket after using it so it's never scanned twice.
Complexity: O(N · L²) time, O(N · L²) space. Each of N words generates L wildcard patterns, each built in O(L).
Reveal the reference solution
from collections import defaultdict, deque def ladder_length(begin, end, words): words = set(words) if end not in words: return 0 buckets = defaultdict(list) for w in words | {begin}: for i in range(len(w)): buckets[w[:i] + "*" + w[i + 1:]].append(w) seen = {begin} queue = deque([(begin, 1)]) while queue: word, steps = queue.popleft() if word == end: return steps for i in range(len(word)): key = word[:i] + "*" + word[i + 1:] for nxt in buckets[key]: if nxt not in seen: seen.add(nxt) queue.append((nxt, steps + 1)) buckets[key] = [] # never scan this bucket again return 0
Follow-ups interviewers ask
- Return all shortest ladders (Word Ladder II).
- Bidirectional BFS.
Frequently asked interview questions
Core interview concepts, complexities, and follow-ups scored by hiring teams.
What is the time complexity of Word Ladder (Shortest Transformation) in Python?
The optimal solution runs in O(N · L²) time and O(N · L²) auxiliary space. Each of N words generates L wildcard patterns, each built in O(L).
What is the brute-force approach, and how do you optimise it?
Compare every pair of words to build edges: O(N² · L) time, O(N²) space. BFS + wildcard buckets: O(N · L²) time, O(N · L²) space. 'h*t' groups hot, hit, hat — neighbours without pairwise comparison. Bidirectional BFS: O(N · L²) time, O(N · L²) space. Much smaller frontiers in practice.
What follow-up questions do interviewers ask about Word Ladder (Shortest Transformation)?
Return all shortest ladders (Word Ladder II). Bidirectional BFS.
