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;
	}
};
posted @ 2014-10-02 10:39  zombies  阅读(218)  评论(0编辑  收藏  举报