127. Word Ladder
题目:
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