给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
思路:
这个题目与127很相似,但是127只需要求出最短路径长,因此只采用BFS就可以满足要求。
现在要求求出所有最短路径,如果还沿用BFS是找不出所有路径的,因此考虑用DFS。
但使用DFS,如果图比较复杂,会发现出现超时。
因此考虑对图进行精简,不能完全构图。
因此考虑讲图进行分层,每一层的某个节点与下一层的所有节点只有某个位置的字母不同,这样实际上图简单不少,与上层的关系接近于有向图,防止遍历到本层时又向上层遍历;在本层间没有连通。
这样构图后,最后一层一定是endWord所在的那一层,因此只要出现某一层出现了endWord,就停止构图。
在这样的图中进行DFS,只要找到了endWord就一定是最短路径那一条,因为每次遍历都是在向下一层遍历,而层数是固定的。
代码值得注意的两个地方:
1.构图:
用一个unordered_map<string,unordered_set<string>>的数据结构表示图,string为当前节点,undered_set<string>为与这个节点相邻的下一层集合。
cur表示当前层,next表示下一层,遍历cur的每个节点,构建好图:graph[*it].insert(tmp),并在下一层中加入:next.insert(tmp)。
另外为了防止遍历到本层时又回到上一层,因此next构建完毕后要讲next层中的节点在字典dict中删去。
最后直到cur层中有endWord才停止,或dict已查找完毕才停止。
2.DFS遍历:
没什么好特别强调的,从beginWord出发,一层一层的遍历节点,直到endWord,将路径加入到result。
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
unordered_map<string,unordered_set<string>> graph;
unordered_set<string> cur;
unordered_set<string> next;
unordered_set<string> dict;
for(int i=0;i<wordList.size();i++)
dict.insert(wordList[i]);
cur.insert(beginWord);
if(dict.count(beginWord)>0)
dict.erase(beginWord);
while(cur.count(endWord)==0&&dict.size()!=0)
{
for(auto it=cur.begin();it!=cur.end();it++)
{
string tmp=*it;
for(int i=0;i<tmp.size();i++)
{
for(int k=0;k<26;k++)
{
tmp[i]=(char)('a'+k);
if(dict.find(tmp)!=dict.end())
{
graph[*it].insert(tmp);
next.insert(tmp);
}
}
tmp=*it;
}
}
if(next.size()==0)
break;
for(auto it=next.begin();it!=next.end();it++)
{
dict.erase(*it);
}
cur=next;
next.clear();
}
vector<vector<string>> result;
if(cur.count(endWord)==0)
return result;
vector<string> input;
dfs(result,input,beginWord,endWord,graph);
return result;
}
private:
void dfs(vector<vector<string>> &result,vector<string> input,string start,string end,unordered_map<string,unordered_set<string>>& graph)
{
if(start==end)
{
input.push_back(start);
result.push_back(input);
return;
}
input.push_back(start);
for(auto it=graph[start].begin();it!=graph[start].end();it++)
{
dfs(result,input,*it,end,graph);
}
return ;
}
};