Skip to content

Word Ladder

Given two words beginWord and endWord, and a dictionary wordList, return the number of words in the shortest transformation sequence from beginWord to endWord. Return 0 if no such sequence exists.

You must change exactly one letter in each transformation, and each transformed word must exist in the word list.

beginWordendWordwordListOutputExplanation
”hit""cog”[“hot”,“dot”,“dog”,“lot”,“log”,“cog”]5Path: hit → hot → dot → dog → cog (5 words total)
“hit""cog”[“hot”,“dot”,“dog”,“lot”,“log”]0No path to “cog” exists
”hot""dog”[“hot”,“dog”,“dot”]3Path: hot → dot → dog (3 words)
  • 1 <= beginWord.length <= 10
  • endWord.length == beginWord.length
  • 1 <= wordList.length <= 5000
  • wordList[i].length == beginWord.length
  • beginWord, endWord, and wordList[i] consist of lowercase English letters
  • beginWord != endWord
  • All the words in wordList are unique
ApproachTimeSpace
BFSO(n*L^2)O(n*L)
Bidirectional BFSO(n*L^2)O(n*L)
★ Recommended
⏱ Time O(n*L^2) 💾 Space O(n*L)
word_ladder_bfs.py
from collections import deque
def ladderLength(beginWord, endWord, wordList):
"""BFS to find shortest transformation sequence."""
wordSet = set(wordList)
if endWord not in wordSet:
return 0
queue = deque([(beginWord, 1)])
visited = {beginWord}
while queue:
word, length = queue.popleft()
if word == endWord:
return length
for i in range(len(word)):
for c in 'abcdefghijklmnopqrstuvwxyz':
if c != word[i]:
new_word = word[:i] + c + word[i+1:]
if new_word in wordSet and new_word not in visited:
visited.add(new_word)
queue.append((new_word, length + 1))
return 0
✓ Simple
⏱ Time O(n*L^2) 💾 Space O(n*L)
word_ladder_bidirectional_bfs.py
from collections import deque
def ladderLength(beginWord, endWord, wordList):
"""Bidirectional BFS for more efficient search."""
wordSet = set(wordList)
if endWord not in wordSet:
return 0
begin_queue, end_queue = deque([beginWord]), deque([endWord])
begin_visited, end_visited = {beginWord}, {endWord}
length = 1
while begin_queue or end_queue:
length += expand(begin_queue, begin_visited, end_visited, wordSet)
if begin_visited & end_visited:
return length
length += expand(end_queue, end_visited, begin_visited, wordSet)
if begin_visited & end_visited:
return length
return 0
def expand(queue, visited, other_visited, wordSet):
if not queue:
return 0
for _ in range(len(queue)):
word = queue.popleft()
for i in range(len(word)):
for c in 'abcdefghijklmnopqrstuvwxyz':
if c != word[i]:
new_word = word[:i] + c + word[i+1:]
if new_word in other_visited:
return 1
if new_word in wordSet and new_word not in visited:
visited.add(new_word)
queue.append(new_word)
return 0