A transformation sequence from word beginWord
to word endWord
using a dictionary wordList
is a sequence of words beginWord -> s1 -> s2 -> ... -> sk
such that:
si
for 1 <= i <= k
is in wordList
. Note that beginWord
does not need to be in wordList
.sk == endWord
Given two words, beginWord
and endWord
, and a dictionary wordList
, return the number of words in the shortest transformation sequence from beginWord
to endWord
, or 0
if no such sequence exists.
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: 5 Explanation: One shortest transformation sequence is "hit" -> "hot" -> "dot" -> "dog" -> cog", which is 5 words long.
Example 2:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"] Output: 0 Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence.
Constraints:
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
wordList
are unique.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy for the Word Ladder problem involves exploring every possible sequence of words to find the shortest transformation path. We start with the beginning word and try every possible one-letter change. We continue this process until we arrive at the ending word.
Here's how the algorithm would work step-by-step:
def word_ladder_brute_force(begin_word, end_word, word_list):
shortest_path_length = float('inf')
all_paths = []
def find_paths(current_word, current_path):
nonlocal shortest_path_length
current_path = current_path + [current_word]
# If we found the end word, record path.
if current_word == end_word:
all_paths.append(current_path)
shortest_path_length = min(shortest_path_length, len(current_path))
return
# Iterate over available words
for next_word in word_list:
if next_word not in current_path:
difference_count = 0
for i in range(len(current_word)):
if current_word[i] != next_word[i]:
difference_count += 1
# Check if the next word is only one letter different
if difference_count == 1:
find_paths(next_word, current_path)
find_paths(begin_word, [])
# If no path was found, the shortest path length will be infinity
if shortest_path_length == float('inf'):
return 0
else:
# Subtract one to get number of transformations instead of word count
return shortest_path_length
The most efficient way to solve this puzzle is to explore words layer by layer, starting from the beginning word. We want to discover the shortest path to the end word by only changing one letter at a time. This is done by exploring words close to the current word before moving further away.
Here's how the algorithm would work step-by-step:
from collections import deque
def word_ladder(begin_word, end_word, word_list):
word_set = set(word_list)
if end_word not in word_set:
return 0
queue = deque([(begin_word, 1)])
visited = {begin_word}
while queue:
current_word, path_length = queue.popleft()
if current_word == end_word:
return path_length
for i in range(len(current_word)):
for char_code in range(ord('a'), ord('z') + 1):
new_char = chr(char_code)
new_word = current_word[:i] + new_char + current_word[i+1:]
# Prevents cycles and redundant paths
if new_word in word_set and new_word not in visited:
queue.append((new_word, path_length + 1))
visited.add(new_word)
return 0
Case | How to Handle |
---|---|
startWord is null or empty | Return 0 immediately as no transformation can start without a start word. |
endWord is null or empty | Return 0 immediately as no transformation can end without an end word. |
wordList is null or empty | Return 0 immediately if wordList is empty and startWord != endWord, as there's nothing to transform to; if startWord == endWord, return 1. |
startWord is equal to endWord | Return 1 immediately as no transformation is needed. |
endWord is not present in the wordList | Return 0 immediately as the transformation is impossible. |
wordList contains duplicate words | The algorithm treats duplicates as single entries, which doesn't affect correctness since we only need to know if a word is reachable, and duplicates don't change reachability. |
No transformation sequence exists between startWord and endWord | The BFS will exhaust all possible paths and return 0 when the endWord is not found. |
Integer overflow if wordList is extremely large and transformation sequence is long | Use appropriate data types (e.g., long) for tracking transformation length to avoid potential integer overflow. |