Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) 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"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
- Return an empty list 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.
通过DFS来确定最短路径的长度,然后进行节点以及该节点能达到的下一节点的关系,但需要逆序存储,这样在求路径的时候可以从endwor出发,这样就可以更快速的求解。
代码如下:
class Solution {
public:
vector<string> tmp;
vector<vector<string>> result_path;
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> curr,next;
unordered_map<string,unordered_set<string>> path;
unordered_set<string> dict;
for(int i=0;i<wordList.size();i++)
dict.insert(wordList[i]);
if(dict.count(beginWord) > 0)
dict.erase(beginWord);
curr.insert(beginWord);
while(curr.count(endWord) == 0 && dict.size() > 0)
{
for(auto it = curr.begin();it!=curr.end();it++)
{
string word = *it;
for(int i=0;i<beginWord.size();i++)
for(char change='a';change<='z';change++)
{
string tmp =word;
tmp[i] = change;
if(dict.count(tmp) > 0)
{
next.insert(tmp);
path[tmp].insert(word);
}
}
}
if(next.empty())
break;
for(auto it = next.begin();it != next.end();it++)
dict.erase(*it);
curr = next;
next.clear();
}
if(curr.count(endWord) > 0)
generatePath(path,endWord,beginWord);
return result_path;
}
void generatePath(unordered_map<string,unordered_set<string>>& path,string start,string end)
{
tmp.push_back(start);
if(start == end)
{
vector<string> rever = tmp;
reverse(rever.begin(),rever.end());
result_path.push_back(rever);
return;
}
for(auto it =path[start].begin();it != path[start].end();it++)
{
generatePath(path,*it,end);
tmp.pop_back();
}
}
};
如何进行优化?对于DFS来说,存在更快的双向DFS,就是分别做起点和终点开始做DFS,每次选取长度短的进行DFS,直到它们在某个节点相遇就结束。
代码如下:
class Solution {
public:
vector<string> tmp_path;
vector<vector<string>> result_path;
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> front,back,next;
unordered_map<string,unordered_set<string>> path;
unordered_set<string> dict;
for(int i=0;i<wordList.size();i++)
dict.insert(wordList[i]);
// dict.erase(beginWord);
//dict.erase(endWord);
front.insert(beginWord);
if(dict.count(endWord))
back.insert(endWord);
bool done = false;
while(done == false && dict.size() > 0)
{
if(front.size() < back.size())
{
for(auto it = front.begin();it!=front.end();it++)
dict.erase(*it);
for(auto it = front.begin();it!=front.end();it++)
{
string word = *it;
for(int i=0;i<word.size();i++)
for(char change='a';change<='z';change++)
{
string tmp =word;
tmp[i] = change;
if(back.count(tmp))
{
done = true;
path[word].insert(tmp);
}
else if(done == false && dict.count(tmp))
{
next.insert(tmp);
path[word].insert(tmp);
}
}
}
front = next;
}
else
{
for(auto it = back.begin();it!=back.end();it++)
dict.erase(*it);
for(auto it = back.begin();it!=back.end();it++)
{
dict.erase(*it);
string word = *it;
for(int i=0;i<word.size();i++)
for(char change='a';change<='z';change++)
{
string tmp =word;
tmp[i] = change;
if(front.count(tmp))
{
done = true;
path[tmp].insert(word);
}
else if(done == false && dict.count(tmp))
{
next.insert(tmp);
path[tmp].insert(word);
}
}
}
back = next;
}
if(next.empty())
break;
next.clear();
}
if(done == true)
generatePath(path,beginWord,endWord);
return result_path;
}
void generatePath(unordered_map<string,unordered_set<string>>& path,string start,string end)
{
tmp_path.push_back(start);
if(start == end)
{
result_path.push_back(tmp_path);
return;
}
for(auto it =path[start].begin();it != path[start].end();it++)
{
generatePath(path,*it,end);
tmp_path.pop_back();
}
}
};
代码写的有点丑陋,双向DFS那一段可以使用递归显的更简洁一点。