126. Word Ladder II
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
for1 <= i <= k
is inwordList
. Note thatbeginWord
does not need to be inwordList
. 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 <= 500
wordList[i].length == beginWord.length
beginWord
,endWord
, andwordList[i]
consist of lowercase English letters.beginWord != endWord
- All the words in
wordList
are unique. - The sum of all shortest transformation sequences does not exceed
105
.
class Solution { // DAG private Map<String, List<String>> map = new HashMap<>(); // 最終result private List<List<String>> result = new ArrayList<>(); public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { // 放入set Set<String> set = new HashSet<>(wordList); set.remove(beginWord); //全域性visited Set<String> visited = new HashSet<>(); // bfs建立DAG /** 關鍵在於dag的建立 1.需要一個層級list去存放這層訪問過的元素,這層結束統一從set中刪除 2.另外透過這個list排重,如果已經入que的不要重複入 */ Queue<String> que = new LinkedList<>(); que.offer(beginWord); set.remove(beginWord); while(!que.isEmpty()) { // 儲存當前層訪問過的元素,便於這層結束的時候統一從set刪除 // 為什麼這麼做? 因為我們不是隻找一條最短路徑,而是要找出所有的, // 所以即使找到一個路徑,還需要找到與這個元素相關的其他路徑 List<String> levelVisited = new ArrayList<>(); int size = que.size(); for(int i = 0; i < size; i++) { String curr = que.poll(); // 遍歷所有neighbor元素 List<String> others = getNeighbors(set, curr); for(String other : others) { levelVisited.add(other); // 將curr放入other的parent 列表 List<String> list = map.getOrDefault(other, new ArrayList<>()); list.add(curr); map.put(other, list); // 如果該元素還沒有入que過,那麼入que if(visited.add(other)) que.offer(other); } } //最終將這層訪問過的元素都刪除 for(String str : levelVisited) { set.remove(str); } } // dfs找到所有路徑 List<String> list = new ArrayList<>(); list.add(endWord); dfs(list, endWord, beginWord, new HashSet<>()); return result; } private void dfs(List<String> currList, String currWord, String beginWord, Set<String> visited) { if(currWord.equals(beginWord)) { var temp = new ArrayList(currList); Collections.reverse(temp); result.add(temp); return; } for(String other : map.getOrDefault(currWord, List.of())) { if(visited.add(other)) { currList.add(other); dfs(currList, other, beginWord, visited); visited.remove(other); currList.remove(currList.size() - 1); } } } private List<String> getNeighbors(Set<String> set, String word) { List<String> list = new ArrayList<>(); for(int i = 0; i < word.length(); i++) { for(int j = 0; j < 26; j++) { char c = (char)('a' + j); String temp = word.substring(0, i) + c + word.substring(i + 1); // 不是自己; 在word列表; if(!temp.equals(word) && set.contains(temp)) list.add(temp); } } return list; } }