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 intermediate word must exist in the word list
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Return
[ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]
Note:
- All words have the same length.
- All words contain only lowercase alphabetic characters.
这道题是找单词衍变所有最短的衍变路径,题目难度为Hard。
题目和第127题相关,大家可以先看下第127题(传送门)。有了第127题的经验,这里就直接采用从两端进行广度优先搜索的方法了,感兴趣的同学可以像第127题一样试下从前向后遍历的方法,看看执行时间上差多少。
每次选择两端中单词个数小的一方进行遍历,由于需要记录所有最短的衍变路径,所以衍变路径上每个单词的下一个可衍变单词都需要记录下来,这里用了unordered_map<string,vector<string>>来存储这些路径信息,以便在最后生成所有路径。还需要注意在路径信息存储时需要判断当前是从前向后遍历还是从后向前遍历,不然存储的信息就乱了。另外,处理第127题时,在字典中找到下一个可衍变单词时即从字典中删除它,而这道题不能在这里进行删除,否则会影响这一层中其他单词查找后续可衍变单词,注意代码中注释掉的这一行,像第127题那样在那里删除是错误的,这道题需要在这一层所有单词都遍历完之后再删除下一层的可衍变单词。最后通过回溯法生成所有衍变路径,这里就不详细说明了。具体代码:
class Solution {
bool getLadders(string bgn, string end, unordered_set<string>& dict, unordered_map<string, vector<string>>& ladder) {
unordered_set<string> head, tail;
bool front2back = true, finish = false;
head.insert(bgn);
tail.insert(end);
while(!head.empty() && !tail.empty()) {
if(head.size() > tail.size()) {
swap(head, tail);
front2back = !front2back;
}
unordered_set<string> next;
for(auto it = head.begin(); it != head.end(); ++it) {
dict.erase(*it);
string cur = *it;
for(int i=0; i<cur.size(); ++i) {
char ch = cur[i];
for(char c='a'; c<='z'; ++c) {
cur[i] = c;
if(tail.find(cur) != tail.end()) {
if(front2back) ladder[*it].push_back(cur);
else ladder[cur].push_back(*it);
finish = true;
}
else if(!finish && dict.find(cur) != dict.end()) {
if(front2back) ladder[*it].push_back(cur);
else ladder[cur].push_back(*it);
next.insert(cur);
//dict.erase(cur);
}
}
cur[i] = ch;
}
}
if(finish) return true;
for(auto s:next) dict.erase(s);
swap(head, next);
}
return false;
}
void getRst(string bgn, string end, unordered_map<string, vector<string>>& ladder, vector<vector<string>>& rst, vector<string>& curRst) {
if(bgn == end) {
rst.push_back(curRst);
return;
}
for(auto s:ladder[bgn]) {
curRst.push_back(s);
getRst(s, end, ladder, rst, curRst);
curRst.pop_back();
}
}
public:
vector<vector<string>> findLadders(string beginWord, string endWord, unordered_set<string> &wordList) {
vector<vector<string>> rst;
vector<string> curRst{beginWord};
unordered_map<string, vector<string>> ladder;
if(getLadders(beginWord, endWord, wordList, ladder))
getRst(beginWord, endWord, ladder, rst, curRst);
return rst;
}
};