DAG bfs + dfs 126,
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; } }