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.
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.
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"]
]
Example 2:
Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
-
Method 1: dfs TLE
class Solution { private int min = Integer.MAX_VALUE >> 1; public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { List<List<String>> result = new ArrayList<>(); Set<String> words = new HashSet<>(wordList); if(!words.contains(endWord)) return result; int len = beginWord.length(); List<String> temp = new ArrayList<String>(); temp.add(beginWord); dfs(result, words, len, endWord, beginWord, temp); return result; } private void dfs(List<List<String>> result, Set<String> words, int len, String endWord, String cur, List<String> temp){ if(cur.equals(endWord)){ if(temp.size() < min){ result.clear(); min = temp.size(); } result.add(new ArrayList<String>(temp)); }else if(temp.size() < min){ for(int i = 0; i < len; i++){ char[] arr = cur.toCharArray(); for(char c = 'a'; c <= 'z'; c++){ arr[i] = c; String next = new String(arr); if(words.contains(next)){ words.remove(next); temp.add(next); dfs(result, words, len, endWord, next, temp); temp.remove(temp.size() - 1); words.add(next); } } arr[i] = cur.charAt(i); } } } }
-
Method 2: bfs AC
class Solution { private Map<String, List<String>> map; public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { List<List<String>> result = new LinkedList<>(); Set<String> words = new HashSet<>(wordList); if(!words.contains(endWord)) return result; words.remove(beginWord); LinkedList<String> queue = new LinkedList<>(); map = new HashMap<>(); int len = beginWord.length(); boolean found = false; queue.add(beginWord); while(!queue.isEmpty() && !found){ int size = queue.size(); Set<String> curLevel = new HashSet<>(); for(int i = 0; i < size; i++){ String cur = queue.poll(); if(cur.equals(endWord)) found = true; char[] arr = cur.toCharArray(); for(int l = 0; l < len; l++){ for(char c = 'a'; c <= 'z'; c++){ if(c == cur.charAt(l)) continue; arr[l] = c; String next = new String(arr); if(words.contains(next) || curLevel.contains(next)){ map.put(cur, !map.containsKey(cur) ? new ArrayList<String>(): map.get(cur)); map.get(cur).add(next); curLevel.add(next); if(words.contains(next)) queue.offer(next); words.remove(next); } } arr[l] = cur.charAt(l); } } } List<String> temp = new LinkedList<>(); temp.add(beginWord); dfs(result, temp, endWord, beginWord); return result; } private void dfs(List<List<String>> result, List<String> temp, String endWord, String cur){ if(cur.equals(endWord)){ result.add(new ArrayList<>(temp)); }else{ if(!map.containsKey(cur)) return; List<String> adj = map.get(cur); for(String s: adj){ temp.add(s); dfs(result, temp, endWord, s); temp.remove(temp.size() - 1); } } } }
- Method 1: bfs + dfs
class Solution { private List<List<String>> result; private Map<String, List<String>> map; public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) { Set<String> wordSet = new HashSet<>(wordList); wordSet.remove(beginWord); this.result = new ArrayList<>(); if(!wordSet.contains(endWord)) return this.result; this.map = new HashMap<>(); Queue<String> q = new LinkedList<>(); q.offer(beginWord); boolean found = false; int len = beginWord.length(); while(!found && !q.isEmpty()){ int size = q.size(); Set<String> nextLevel = new HashSet<>(); for(int i = 0; i < size; i++){ String temp = q.poll(); if(temp.equals(endWord)) found = true; char[] arr = temp.toCharArray(); for(int j = 0; j < len; j++){ char origin = arr[j]; for(char c = 'a'; c <= 'z'; c++){ if(c == origin) continue; arr[j] = c; String next = new String(arr); if(wordSet.contains(next) || nextLevel.contains(next)){ List<String> list = map.containsKey(temp) ? map.get(temp): new ArrayList<>(); list.add(next); map.put(temp, list); nextLevel.add(next); if(wordSet.contains(next)) q.offer(next); wordSet.remove(next); } } arr[j] = origin; } } } List<String> temp = new ArrayList<>(); temp.add(beginWord); dfs(temp, endWord, beginWord); return this.result; } private void dfs(List<String> temp, String end, String cur){ if(cur.equals(end)) this.result.add(new ArrayList<String>(temp)); else{ if(!map.containsKey(cur)) return; List<String> adj = map.get(cur); for(String s: adj){ temp.add(s); dfs(temp, end, s); temp.remove(temp.size() - 1); } } } }