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 transformed word must exist in the word list. Note that beginWord is not a transformed word.
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log","cog"]
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.
- You may assume no duplicates in the word list.
- You may assume beginWord and endWord are non-empty and are not the same.
UPDATE (2017/1/20):
The wordList parameter had been changed to a list of strings (instead of a set of strings). Please reload the code definition to get the latest changes.
class Solution { public: int ladderLength(string beginWord, string endWord, vector<string>& wordList) { unordered_set<string> us(wordList.begin(), wordList.end()); if (us.find(endWord) == us.end()) return 0; unordered_set<string> visited; unordered_set<string> q1; unordered_set<string> q2; visited.insert(beginWord); q1.insert(beginWord); q2.insert(endWord); int step = 0; while (!q1.empty() && !q2.empty()) { unordered_set<string> temp; if (q2.size() < q1.size()) { swap(q1,q2); } for(auto cur : q1) { //cout << cur << endl; if (q2.find(cur) != q2.end()) { return step+1; } visited.insert(cur); for (int j = 0; j < beginWord.size(); j++) { for (int k = 0 ; k < 26;k++) { string y = cur; y[j] = 'a' + k; if (y[j]==cur[j]) { continue; } if (us.find(y) != us.end() && visited.find(y) == visited.end()) { temp.insert(y); } } } } step ++; q1 = q2; q2 = temp; } return 0; } };
1 class Solution { 2 public: 3 int ladderLength(string beginWord, string endWord, vector<string>& wordList) { 4 5 unordered_set<string> us(wordList.begin(), wordList.end()); 6 if (us.find(endWord) == us.end()) 7 return 0; 8 unordered_set<string> visited; 9 queue<string> q; 10 visited.insert(beginWord); 11 q.push(beginWord); 12 int step = 0; 13 while (!q.empty()) { 14 int sz = q.size(); 15 for(int i = 0 ; i< sz; i++){ 16 string cur = q.front(); q.pop(); 17 if (cur == endWord) { 18 return step+1; 19 } 20 for (int j = 0; j < beginWord.size(); j++) { 21 for (int k = 0 ; k < 26;k++) { 22 string y = cur; 23 y[j] = 'a' + k; 24 if (y[j]==cur[j]) { 25 continue; 26 } 27 if(us.find(y) != us.end() && visited.find(y) == visited.end()) { 28 q.push(y); 29 visited.insert(y); 30 } 31 } 32 } 33 } 34 step ++; 35 } 36 return 0; 37 } 38 };
这道题是经典的广度有优先搜索的例子,也是Dijkstra's algorithm的变形。
以题目给出的例子为例,其实就是在所有路径的权重都为1的情况下求出下列无向图中从节点hit到节点cog的最短路径:

PS:图中相互之间只相差一个字母的单词都是相邻节点。
利用BFS算法,维持两个集合: visited 和 wordSet

从hit开始出发,找到唯一的相邻节点:hot, 把它放进visited中,第一次循环结束。 PS: 所谓找到相邻的节点,在题目中就是找出和该单词之相差一个字母的所有单词。请看最后代码的详细实现。

查看hot节点的所有相邻节点(已经被访问过的hit除外),找到lot和dot, 放进visited中。第二次循环结束。

找出新家进来的lot和dot的未被访问的相邻节点,分别是log和dog放进visited中。第三次循环结束。

找出log的未被访问的相邻节点cog,放进结合中。第四次循环结束。由于cog就是endWord,任务结束,跳出循环。

这里总共经历了四次循环,每循环一次,其实就是从beginWord想endWord变化的一步,因此循环的次数(加上1)就是从beginWord想endWord转变经历的 number of steps。
1 class Solution: 2 def ladderLength(self, beginWord, endWord, wordList): 3 """ 4 :type beginWord: str 5 :type endWord: str 6 :type wordList: List[str] 7 :rtype: int 8 """ 9 wordList = set(wordList) 10 visited = [beginWord] 11 visited = set(visited) 12 dist = 1 13 14 while endWord not in visited: 15 temp = set() 16 for word in visited: 17 for i in range(len(word)): 18 newwordL = list(word) 19 for ch in 'qwertyuiopasdfghjklzxcvbnm': 20 newwordL[i] = ch 21 newWord = ''.join(newwordL) 22 if newWord in wordList: 23 temp.add(newWord) 24 wordList.remove(newWord) 25 26 dist += 1 27 if len(temp) == 0: # if 0, it never gets to the endWord 28 return 0 29 30 visited = temp 31 32 return dist
参考链接:https://www.jianshu.com/p/753bd585d57e