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
题意:给出起始词start和目的词end,以及字典dict,要求找到所有从start到end的最短路径,满足:
(1)路径上每个词都在dict中
(2)路径上相邻的词只能相差一个字母
给出的所有词长度相同,均由小写字母构成。
分析:比较难得一道图论题。
首先,基本思想是用BFS搜索可行路径,如果想要更快可以用双向BFS。然后用DFS记录路径。
其次,在每次搜索时,如何搜索下一步的单词,一开始我直接遍历的字典找和当前词距离为1的,这样显然会超时。。后来看到别人的方法为遍历单词的每个位置,枚举26个字母的所有情况,找这个新词是否在字典中出现,搜索空间只有L*26,L为单词长度。
在搜索可行路径时,要注意:(1)之前搜索过得词不能再搜索到,否则会成环,处理方法是每次BFS新的一层时,将上一层的词从dict字典删除。
(2)一次BFS之后,搜索到的所有新词要去重,因为BFS层与层之间存在多对多关系,所有不去重会造成搜索空间很大,内存溢出。这里用两个unordered_set存储上一层的词和当前层搜索到的词
最后,用一个unordered_map<string,vector<string>> 记录路径,每个元素的value记录key的前趋词表,记录前趋才能去除冗余,若记录后继词表,会有很多不可行路径。BFS后,用DFS遍历这个map记录结果。
代码:
class Solution {
private:
int caldis(string x,string y)
{
int dis = 0;
for(int i=0; i<x.length(); i++)
if(x[i]!=y[i])
dis++;
return dis;
}
void dfs(unordered_map<string,vector<string> > &mp,string cur,vector<string> &now,vector<vector<string> > &ans)
{
now.push_back(cur);
if(mp[cur].size()==0)
{
vector<string> tmp(now);
reverse(tmp.begin(),tmp.end());
ans.push_back(tmp);
now.pop_back();
return;
}
for(int i=0; i<mp[cur].size(); i++)
{
dfs(mp,mp[cur][i],now,ans);
}
now.pop_back();
}
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
vector<string> now;
vector<vector<string> > ans;
if(start==end)
{
now.push_back(end);
ans.push_back(now);
return ans;
}
unordered_set<string> qu[2];
unordered_map<string,vector<string> > mp;
for(auto it=dict.begin(); it!=dict.end(); it++)
{
mp[*it] = vector<string>();
}
qu[0].insert(start);
int i=0;
bool isdone = false;
while(!qu[i].empty())
{
i = 1-i;
qu[i].clear();
for(auto it=qu[1-i].begin(); it!=qu[1-i].end(); it++)
{
if(caldis(*it,end)==1)
{
isdone = true;
mp[end].push_back(*it);
}
dict.erase(*it);
}
if(isdone) break;
for(auto it=qu[1-i].begin(); it!=qu[1-i].end(); it++)
{
string cur = *it;
for(int j=0; j<cur.size(); j++)
{
for(char ch='a'; ch<='z'; ch++)
{
string tmp = cur;
tmp[j] = ch;
if(dict.find(tmp)!=dict.end())
{
mp[tmp].push_back(cur);
qu[i].insert(tmp);
}
}
}
}
}
ans.clear();
now.clear();
if(!isdone) return ans;
dfs(mp,end,now,ans);
return ans;
}
};