Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWordto 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
.
解答:
用BFS。层次遍历,得到最短路径
To simplify the problem, we insert end
into dict
. Once we meet end
during the BFS, we know we have found the answer. We maintain a variable dist
for the current distance of the transformation and update it by dist++
after we finish a round of BFS search (note that it should fit the definition of the distance in the problem statement). Also, to avoid visiting a word for more than once, we erase it from dict
once it is visited.
代码如下:
class Solution {
public:
void toVisit(string& word, queue<string>& q, unordered_set<string>& wordList){
wordList.erase(word);
for(int i = 0; i < word.size(); i++){
char temp = word[i];
for(int j = 0; j < 26; j++){
word[i] = 'a'+ j;
if(wordList.find(word) != wordList.end()){
q.push(word);
wordList.erase(word);
}
}
word[i] = temp;
}
}
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordList) {
wordList.insert(endWord);
queue<string> res;
toVisit(beginWord, res, wordList);
int count = 2;
while(!res.empty()){
int len = res.size();
for(int i = 0; i < len; i++){
string word = res.front();
res.pop();
if(word == endWord) return count;
toVisit(word, res, wordList);
}
count++;
}
return 0;
}
};
另一个更高效的代码,暂时还没理解:
The above code can still be speeded up if we also begin from end
. Once we meet the same word from start
and end
, we know we are done. This link provides a nice two-end search solution. I rewrite the code below for better readability. Note that the use of two pointers phead
and ptail
save a lot of time. At each round of BFS, depending on the relative size of head
and tail
, we pointphead
to the smaller set to reduce the running time.
class Solution {
public:
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordDict) {
unordered_set<string> head, tail, *phead, *ptail;
head.insert(beginWord);
tail.insert(endWord);
int dist = 2;
while (!head.empty() && !tail.empty()) {
if (head.size() < tail.size()) {
phead = &head;
ptail = &tail;
}
else {
phead = &tail;
ptail = &head;
}
unordered_set<string> temp;
for (auto itr = phead -> begin(); itr != phead -> end(); itr++) {
string word = *itr;
wordDict.erase(word);
for (int p = 0; p < (int)word.length(); p++) {
char letter = word[p];
for (int k = 0; k < 26; k++) {
word[p] = 'a' + k;
if (ptail -> find(word) != ptail -> end())
return dist;
if (wordDict.find(word) != wordDict.end()) {
temp.insert(word);
wordDict.erase(word);
}
}
word[p] = letter;
}
}
dist++;
swap(*phead, temp);
}
return 0;
}
};