Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["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.
这次是要打印所有道路
1.一开始用一个queue<vector<string> > 记录每一步的路径,超内存
class Solution {
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
minn = 2147483647;
queue<string> Q;
queue<vector<string> > disQ;
Q.push(start);
disQ.push(vector<string> {start});
while(!Q.empty()){
string head = Q.front();
Q.pop();
vector<string> headDis = disQ.front();
//printVector<string>(headDis);
int ladderSize = headDis.size();
if(ladderSize + 2 > minn){
return ans;
}
disQ.pop();
for(unsigned int l = 0; l < head.length(); ++l){
string str = head;
for(char ch = 'a'; ch <= 'z' ; ++ch)
if(ch != head[l]){
str[l] = ch;
if(str == end){
minn = min(minn, ladderSize + 2);
headDis.push_back(end);
ans.push_back(headDis);
headDis.pop_back();
}
else if(dict.find(str) != dict.end()){
bool flag = true;
for(auto word : headDis){
if(word == str){
flag = false;
break;
}
}
if(flag){
Q.push(str);
headDis.push_back(str);
disQ.push(headDis);
headDis.pop_back();
}
}
}
}
}
return ans;
}
private:
int minn;
vector<vector<string> > ans;
};
2.后来想到只记录队列中的前驱节点,还是超内存= =
class Solution {
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
minn = 2147483647;
vector<string> Q;
vector<int> pre;
queue<int> dis;
Q.push_back(start);
pre.push_back(-1);
dis.push(1);
int headPtr = 0;
while(Q.size() > headPtr){
string head = Q[headPtr];
int ladderSize = dis.front();
dis.pop();
if(ladderSize + 1 > minn){
break;
}
for(unsigned int l = 0; l < head.length(); ++l){
string str = head;
for(char ch = 'a'; ch <= 'z' ; ++ch)
if(ch != head[l]){
str[l] = ch;
if(str == end){
minn = min(minn, ladderSize + 1);
vector<string> route;
int k = headPtr;
while(k != -1){
route.insert(route.begin(), Q[k]);
k = pre[k];
}
route.push_back(end);
ans.push_back(route);
}
else if(dict.find(str) != dict.end()){
bool flag = true;
int k = headPtr;
while(k != -1){
if(Q[k] == str){
flag = false;
break;
}
k = pre[k];
}
if(flag){
Q.push_back(str);
pre.push_back(headPtr);
dis.push(ladderSize + 1);
}
}
}
}
++headPtr;
}
return ans;
}
private:
int minn;
vector<vector<string> > ans;
};
3.所以考虑先把最小路程用bfs求出来,再dfs产生所有路径。其中还有一些可以优化的点,具体可以参考 http://www.tuicool.com/articles/eaQNNr
最后但是如果用bfs产生邻接表(注释中的)会比用上面文章中的方法慢一倍。。暂时没有搞明白为什么,初步猜测是hash的unordered_map查询消耗了时间。
class Solution {
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
minn = 2147483647;
calcMinRoute(start, end, dict);
vector<string> ladder{end};
calcAllRoutes(start, end, ladder);
return ans;
}
private:
int minn;
vector<vector<string> > ans;
unordered_map<string, int> level;
unordered_map<string, unordered_set<string> > adj;
/* void calcMinRoute(string start, string end, unordered_set<string> &dict){
dict.insert(end);
queue<string> Q;
Q.push(start);
level[start] = 1;
while(!Q.empty()){
string head = Q.front();
Q.pop();
if(minn < level[head] + 1){
return;
}
for(unsigned int l = 0; l < head.length(); ++l){
string str = head;
for(char ch = 'a'; ch <= 'z' ; ++ch)
if(ch != head[l]){
str[l] = ch;
if(dict.find(str) != dict.end() && (level[str] == 0 || level[str] == level[head] + 1)){
if(level[str] == 0){
<span style="white-space:pre"> </span>Q.push(str);
level[str] = level[head] + 1;
}
adj[str].insert(head);
}
if(str == end){
minn = level[head] + 1;
}
}
}
}
return;
}
*/
void calcMinRoute(string start, string end, unordered_set<string> &dict){
unordered_set<string> current_level;
unordered_set<string> next_level;
unordered_set<string> unvisited(dict);
unvisited.erase(start);
current_level.insert(start);
while(current_level.count(end) == 0 && unvisited.size() > 0){
for(auto word : current_level){
for(int l = 0; l < word.length(); ++l){
string tmp = word;
for(char ch = 'a'; ch <= 'z'; ++ch)
if(ch != word[l]){
tmp[l] = ch;
if(unvisited.count(tmp) > 0){
next_level.insert(tmp);
adj[tmp].insert(word);
}
}
}
}
for(auto word : next_level){
unvisited.erase(word);
}
if(next_level.size() == 0) {
break;
}
current_level = next_level;
next_level.clear();
}
}
void calcAllRoutes(string target, string now, vector<string> &ladder){
if(now == target){
ans.push_back(ladder);
return;
}
for(auto next : adj[now]){
ladder.insert(ladder.begin(), next);
calcAllRoutes(target, next, ladder);
ladder.erase(ladder.begin());
}
return;
}
};