Description
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that:
- Only one letter can be changed at a time
- Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
- Return an empty list if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
UPDATE (2017/1/20):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.
Solution
BFS, time O(n ^ 2), space?
跟"Word Ladder"相同的思路,用一种类似Dijkistra的算法来做。将beginWord to currWord的所有ladder保存在map中即可。注意current level words需要在当前层全部遍历完毕之后再全部从dict中移除掉,否则只会找到一条ladder,而题目中要求找到所有最短的ladder。
class Solution {
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
Set<String> dict = new HashSet<>();
dict.addAll(wordList);
Queue<String> queue = new LinkedList<>();
queue.offer(beginWord);
Map<String, List<List<String>>> word2ladders = new HashMap<>();
List<List<String>> list = new ArrayList<>();
list.add(Arrays.asList(beginWord));
word2ladders.put(beginWord, list);
dict.remove(beginWord); // don't forget to remove beginWord from dict
// stop loop is queue is empty or target path to endWord already found
while (!queue.isEmpty() && !word2ladders.containsKey(endWord)) {
Set<String> nextLevelWords = new HashSet<>(); // store next level words
while (!queue.isEmpty()) { // traverse current level words
String curr = queue.poll();
char[] arr = curr.toCharArray();
for (int i = 0; i < arr.length; ++i) {
char tmp = arr[i];
for (char c = 'a'; c <= 'z'; ++c) {
if (c == tmp) { // skip curr it self
continue;
}
arr[i] = c;
String next = new String(arr);
if (!dict.contains(next)) {
continue;
}
nextLevelWords.add(next);
if (!word2ladders.containsKey(next)) {
word2ladders.put(next, new ArrayList<>());
}
for (List<String> path : word2ladders.get(curr)) {
List<String> nextPath = new ArrayList<>(path);
nextPath.add(next);
word2ladders.get(next).add(nextPath);
}
}
arr[i] = tmp;
}
}
dict.removeAll(nextLevelWords); // nextLevelWords should be marked as visited
queue.addAll(nextLevelWords); // add all nextLevelWords to the queue
}
return word2ladders.getOrDefault(endWord, Collections.EMPTY_LIST);
}
}