题目:
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.
思路:
为了减少搜索量,我们采用从两头向中间同时搜索的策略。也就是说,分别设立两个hash表,一个初始化为beginWord,一个初始化为endWord,然后在wordList里面查找和hash表相邻的节点。一旦发现了,则有两种情况:1)该相邻节点已经存在于另外一个hash表中。此时说明从两头开始的搜索已经相遇,我们找到了最短路径,所以直接返回;否则将该相邻节点插入hash表中,继续查找即可。
本质上来讲,本题也算是很标准的广度优先搜索了。为了减少搜索量,我们每次搜索完一层后,都从size比较小的一个hash表开始下一层的搜索。当然这只是属于实现层面的小技巧而已。
代码:
class Solution {
public:
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordList) {
int res = 1;
unordered_set<string> set1{beginWord};
unordered_set<string> set2{endWord};
while(set1.size() > 0) {
res++;
unordered_set<string> set;
for(auto word : set1) {
wordList.erase(word);
}
for(auto word : set1) {
for(size_t i = 0; i < word.size(); ++i) {
string next = word;
for(char c = 'a'; c != 'z'; ++c) {
next[i] = c;
if(wordList.find(next) == wordList.end()) {
continue;
}
if(set2.find(next) != set2.end()) {
return res;
}
set.insert(next);
}
}
}
set1 = set.size() < set2.size() ? set : set2; // set1 is the one with smaller size
set2 = set.size() < set2.size() ? set2 : set; // set2 is the one with larger size
}
return 0;
}
};