..
126. Word Ladder II
Problem Description
A transformation sequence from word beginWord to word endWord using a dictionary wordList is a sequence of words beginWord -> s1 -> s2 -> ... -> sk
such that:
Every adjacent pair of words differs by a single letter.
Every 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 all the shortest transformation sequences from beginWord to endWord, or an empty list if no such sequence exists. Each sequence should be returned as a list of the words [beginWord, s1, s2, ..., sk].
Example 1:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
Output: [["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]
Explanation: There are 2 shortest transformation sequences:
"hit" -> "hot" -> "dot" -> "dog" -> "cog"
"hit" -> "hot" -> "lot" -> "log" -> "cog"
Example 2:
Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore there is no valid transformation sequence.
Constraints:
1 <= beginWord.length <= 5
endWord.length == beginWord.length
1 <= wordList.length <= 1000
wordList[i].length == beginWord.length
beginWord, endWord, and wordList[i] consist of lowercase English letters.
beginWord != endWord
All the words in wordList are unique.
Solution
Python
from collections import deque, defaultdict
class Solution:
def __init__(self):
self.distance = {}
self.neighbors = {}
def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]:
path = []
if not self.find_ladder_length(beginWord, endWord, wordList):
return path
self.dfs(path, endWord, [], beginWord)
return path
def dfs(self, result, end, curr_path, curr_word):
if curr_word == end:
result.append(curr_path[:] + [curr_word])
return
for next_word in self.neighbors[curr_word]:
if next_word in self.distance and self.distance[next_word] < self.distance[curr_word]:
curr_path.append(curr_word)
self.dfs(result, end, curr_path, next_word)
curr_path.pop()
def find_ladder_length(self, beginWord, endWord, wordList):
if not beginWord or len(beginWord) == 0 or \
not endWord or len(endWord) == 0 or \
not wordList or len(wordList) == 0 or \
len(beginWord) != len(endWord):
return False
wordList = set(wordList)
wordList.add(beginWord)
word_queue = deque([endWord])
seen = set([endWord])
steps = 1
while word_queue:
size = len(word_queue)
for _ in range(size):
curr_word = word_queue.popleft()
self.distance[curr_word] = steps
next_words = self._gen_new_words(curr_word, wordList)
self.neighbors[curr_word] = next_words
if curr_word == beginWord:
return True
for next_word in next_words:
if next_word not in seen:
word_queue.append(next_word)
seen.add(next_word)
steps += 1
return False
def _gen_new_words(self, curr_word, wordList):
new_words = []
for i in range(len(curr_word)):
for code in 'abcdefghijklmnopqrstuvwxyz':
if curr_word[i] == code:
continue
tmp_word = curr_word[:i] + code + curr_word[i + 1:]
if tmp_word in wordList:
new_words.append(tmp_word)
# wordList.remove(tmp_word)
return new_words
Java
class Solution {
private Map<String, Set<String>> graph;
private List<List<String>> result;
private Map<String, Integer> distance;
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
distance = new HashMap<>();
graph = buildGraph(beginWord, wordList);
result = new ArrayList<>();
dfs(beginWord, endWord, new ArrayList<>());
return result;
}
private void dfs(String word, String target, List<String> solution) {
solution.add(word);
if (target.equals(word)) {
result.add(solution);
} else {
for (String child : graph.get(word)) {
if (distance.get(word) + 1 == distance.getOrDefault(child, Integer.MAX_VALUE)) {
dfs(child, target, new ArrayList<>(solution));
}
}
}
}
private Map<String, Set<String>> buildGraph(String beginWord, List<String> wordList) {
Map<String, Set<String>> map = new HashMap<>();
Queue<String> queue = new LinkedList<>();
queue.add(beginWord);
distance.put(beginWord, 0);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
String word = queue.poll();
Set<String> set = map.getOrDefault(word, new HashSet<>());
map.put(word, set);
for (String s : wordList) {
int cnt = 0;
for (int j = 0; j < word.length(); j++) {
if (s.charAt(j) != word.charAt(j)) {
cnt++;
}
}
if (cnt == 1) {
if (!distance.containsKey(s)) {
queue.add(s);
distance.put(s, distance.get(word) + 1);
}
set.add(s);
}
}
}
}
return map;
}
}
Complexity Analysis