題目:
Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the word list
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
鏈接: http://leetcode.com/problems/word-ladder/
題解:
一上來無思路,想象跟Dijkstra單源最短路徑很像,但不知道怎么寫。於是大肆搜刮資料,主要參考了code ganker和小瑩子的代碼和post。寫的話和Binary Tree Level Order Traversal很接近,就是標准的用queue和一個visited數組或者hashset來標記訪問過的元素,用curLevel和nextLevel來記錄哪一層BFS。 圖的算法需要多練習,相信練好了就會像打開眾秒之門一樣。
Time Complexity - O(min(26^L, size(wordList)), Space Complexity - O(min(26^L, size(wordList)), L為 word length
public class Solution { public int ladderLength(String beginWord, String endWord, Set<String> wordList) { if(beginWord == null || endWord == null || wordList == null || wordList.size() == 0 || beginWord.equals(endWord)) return 0; Queue<String> q = new LinkedList<>(); q.offer(beginWord); int curLevel = 1, nextLevel = 0, steps = 1; HashSet<String> visited = new HashSet<>(); while(!q.isEmpty()) { String word = q.poll(); curLevel--; for(int i = 0; i < word.length(); i++) { char[] wordArray = word.toCharArray(); for(char j = 'a'; j <= 'z'; j++) { wordArray[i] = j; String newWord = String.valueOf(wordArray); if(newWord.equals(endWord)) return steps + 1; if(wordList.contains(newWord) && !visited.contains(newWord)) { q.offer(newWord); visited.add(newWord); nextLevel++; } } } if(curLevel == 0) { curLevel = nextLevel; nextLevel = 0; steps++; } } return 0; } }
二刷:
Java:
One-way BFS:
復雜度並不好計算,我們每一次找到新單詞以后,要計算26個字母組合的可能性,對於每一個新組成的單詞,我們要判斷是存在於set里。branching factor = 26,depth = 單詞長度L,set中的查找我們粗略算為O(1),所以這一部分的復雜度就是26 ^ L。假如我們有x個單詞滿足條件,那么接下來我們要對這x個單詞進行同樣的步驟。最壞情況下我們要檢查set中所有的n個單詞,所以時間復雜度應該是O(n * 26L ) , 空間復雜度也一樣。
Time Complexity - O(n * 26L), Space Complexity - O(n * 26L)
public class Solution { public int ladderLength(String beginWord, String endWord, Set<String> wordList) { if (beginWord == null || endWord == null || wordList == null) return 0; Queue<String> q = new LinkedList<>(); q.offer(beginWord); int steps = 1, curLevel = 1, nextLevel = 0; Set<String> visited = new HashSet<>(5000); visited.add(beginWord); while (!q.isEmpty()) { String word = q.poll(); char[] wordArr = word.toCharArray(); curLevel--; for (int i = 0; i < wordArr.length; i++) { char tmp = wordArr[i]; for (char c = 'a'; c <= 'z'; c++) { if (c != tmp) wordArr[i] = c; String newWord = String.valueOf(wordArr); if (newWord.equals(endWord)) return steps + 1; if (!visited.contains(newWord) && wordList.contains(newWord)) { q.offer(newWord); nextLevel++; visited.add(newWord); } } wordArr[i] = tmp; } if (curLevel == 0) { curLevel = nextLevel; nextLevel = 0; steps++; } } return 0; } }
三刷:
三刷使用了 Two-way BFS。存兩個HashSet beginSet和endSet,然后每次從較小的hashset開始進行下一步的計算,把BFS的結果存在一個tmp HashSet中。最后更新beginSet = tmp。 其他過程跟1-way BFS基本一樣,不同的一點是,假如newWord存在於endSet中,我們立刻可以返回steps + 1。 這里新建立一個wordList的copy,再從其中移除已訪問過的單詞,也可以增加一些速度。
代碼主要參考了@Moriarty。
Java:
Time Complexity - O(n * 26L), Space Complexity - O(n * 26L)
public class Solution { public int ladderLength(String beginWord, String endWord, Set<String> wordList) { if (beginWord == null || endWord == null || wordList == null || beginWord.equals(endWord)) return 0; Set<String> beginSet = new HashSet<>(wordList.size()); Set<String> endSet = new HashSet<>(wordList.size()); Set<String> list = new HashSet(wordList); //have a copy of input beginSet.add(beginWord); endSet.add(endWord); int steps = 1, curLevel = 1, nextLevel = 0; while (!beginSet.isEmpty() && !endSet.isEmpty()) { if (beginSet.size() > endSet.size()) { Set<String> set = beginSet; beginSet = endSet; endSet = set; } Set<String> tmpSet = new HashSet<String>(); for (String word : beginSet) { char[] wordArr = word.toCharArray(); for (int i = 0; i < wordArr.length; i++) { char ch = wordArr[i]; for (char c = 'a'; c <= 'z'; c++) { wordArr[i] = c; String newWord = String.valueOf(wordArr); if (endSet.contains(newWord)) return steps + 1; if (list.contains(newWord)) { list.remove(newWord); tmpSet.add(newWord); } } wordArr[i] = ch; } } beginSet = tmpSet; steps++; } return 0; } }
四刷:
class Solution { public int ladderLength(String beginWord, String endWord, List<String> wordList) { if (beginWord == null || endWord == null || wordList == null) return 0; Queue<String> q = new LinkedList<>(); q.offer(beginWord); int steps = 1, curLevel = 1, nextLevel = 0; Set<String> visited = new HashSet<>(5000); visited.add(beginWord); Set<String> set = new HashSet<>(); for (String word : wordList) set.add(word); while (!q.isEmpty()) { String word = q.poll(); char[] wordArr = word.toCharArray(); curLevel--; for (int i = 0; i < wordArr.length; i++) { char tmp = wordArr[i]; for (char c = 'a'; c <= 'z'; c++) { if (c != tmp) wordArr[i] = c; String newWord = String.valueOf(wordArr); if (!visited.contains(newWord) && set.contains(newWord)) { if (newWord.equals(endWord)) return steps + 1; q.offer(newWord); nextLevel++; visited.add(newWord); } } wordArr[i] = tmp; } if (curLevel == 0) { curLevel = nextLevel; nextLevel = 0; steps++; } } return 0; } }
Reference:
http://blog.csdn.net/linhuanmars/article/details/23029973
http://www.cnblogs.com/springfor/p/3893499.html
http://www.programcreek.com/2012/12/leetcode-word-ladder/
http://www.geeksforgeeks.org/breadth-first-traversal-for-a-graph/
https://leetcode.com/discuss/48083/share-python-solutions-concise-160ms-optimized-solution-100ms
https://leetcode.com/discuss/50930/java-solution-using-dijkstras-algorithm-with-explanation
https://leetcode.com/discuss/42006/easy-76ms-c-solution-using-bfs
https://leetcode.com/discuss/44079/super-fast-java-solution-using-two-end-bfs
https://leetcode.com/discuss/43940/another-accepted-java-solution-bfs
https://leetcode.com/discuss/28573/share-my-two-end-bfs-in-c-80ms
https://leetcode.com/discuss/68935/two-end-bfs-in-java-31ms
https://leetcode.com/discuss/30872/short-java-bfs-solution
https://leetcode.com/discuss/20587/accepted-java-solution-based-on-dijkstras-algorithm
https://leetcode.com/discuss/23274/a-c-bfs-solution-without-constructing-words
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-spring-2008/recitations/recitation12.pdf