LeetCode-Word Ladder II-单词梯-BFS搜索构图+DFS
https://oj.leetcode.com/problems/word-ladder-ii/
首先,要打印出所有路径,就必须用到DFS+pre的技术。因此需要构造出这个图,又因为需要打印出最短距离,所以构造图的同时还需要知道到终点的最短路径。
构造图如果枚举所有点对会超时,O(n^2)算法不可行。
考虑使用BFS搜索构造足够打印所有最短路径的图。从start节点出发,枚举他可能变化成的所有词典单词,BFS拓展节点。
需要注意的事项有两个:
1)必须要保证队列中不能出现过以前出现过的单词,因为这样会使图特别大,并且从以前加入队列的单词再出发BFS不会使得路径更短。
2)必须要保证以按层次搜索的角度来看,任一节点v上一层的所有前继节点到v的边都被构造在图中。
研究了很久发现,用一个levels[]来记录每个节点的深度值可以做到这一点。这其中对BFS的修改有三处:
1)初始化levels[]为INF,并时刻判断一个出队列节点的深度是否大于等于end的深度,如果大于等于,就不展开该节点,这样保证图不会构造的太大。
2)保证队列单词不会重复,levels[v]!=INF时,不要加入队列。
3)u是出队节点,保证levels[v]>levels[u]时有一条u->v的边。
构造出这个图之后,再进行一次DFS,这时需要注意一点可能这个图中存在长于到end最短路径(之前并没有及时停止,多加入了下层的一些节点)。所以需要保证DFS深度不超过end节点的level。
使用pre在DFS过程记录每个节点的前驱节点,当遇到end时,反向遍历到start并将这个路径加入结果即可。
代码如下:
typedef unordered_set<string> scset;
typedef unordered_set<string>::iterator sciter;
typedef pair<int,int> scpair;
const int INF=9999;
class Solution {
public:
int m,n;
vector<vector<int>> g;
unordered_map <string,int> cm;
vector <string> elems;
vector<vector<string>> tot;
string end;
vector <int> pres;
vector <bool> vis;
int minL;
vector <int> levels;
void DFS(int u,int l){
if (l>minL){return;}
if (elems[u]==elems[1]){
tot.push_back(vector<string>());
vector <string> &cur=tot[tot.size()-1];
for (int i=u;i!=-1;i=pres[i]){
cur.push_back(elems[i]);
}
reverse(cur.begin(),cur.end());
return;
}
for (int i=0;i<g[u].size();i++){
int v=g[u][i];
pres[v]=u;
DFS(v,l+1);
}
}
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
m=start.length();
sciter it=dict.find(start);
if (it!=dict.end()){dict.erase(it);}
it=dict.find(end);
if (it!=dict.end()){dict.erase(it);}
n=dict.size()+2;
g.resize(n,vector<int>());
elems.resize(n);
elems[0]=start;
elems[1]=end;
cm[start]=0;
cm[end]=1;
int count=2;
for (sciter it=dict.begin();it!=dict.end();it++){
elems[count]=*it;
cm[*it]=count;
count++;
}
list <int> que;
que.push_back(0);
dict.insert(end);
levels.resize(n,INF);
levels[0]=0;
while(!que.empty()){
int u=que.front();
que.pop_front();
string us=elems[u];
if (levels[u]>=levels[1]){continue;} //not longer, we just need the shortest path
for (int i=0;i<m;i++){ //all possible changes from cur node
for (int j=0;j<26;j++){
string us=elems[u];
char nc=j+'a';
if (nc==us[i]){continue;}
string vs=us;
vs[i]=nc;
sciter it=dict.find(vs);
if (it!=dict.end()){ //we have a edge from u->v
int v=cm[vs];
if (levels[v]>levels[u]){ //ensure a DAG is constructed
g[u].push_back(v);
}
if (levels[v]!=INF){ //ensure not repeat
continue;
}
levels[v]=levels[u]+1; //node's not repeat, the level is unique for every word
que.push_back(v);
}
}
}
}
minL=levels[1];
vis.assign(n,false);
pres.resize(n,-1);
DFS(0,0);
return tot;
}
};
浙公网安备 33010602011771号