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
给定两个单词,和一个词典,找出这两个单词间的所有最短转换,所有的中间转换单词都要在词典中。
由于求得是最短的路径 我们采用宽度优先搜索,当第一次找到的时候,就是最短的路径。
一开始的做法是,用一个队列实现宽度优先遍历,队列中存储着单词和到达这个单词的路径,每次遍历单词的临近单词,若其在词典中,将临近单词和临近单词的路径都压入队列中,但这样会产生超时的错误,因为同一个单词可能会被压入多次,进行了很多多余操作,虽然这不影响结果正确性,却消耗大量时间。
改进的算法,将所有到达某一单词的路径集中映射到单词中,即用hash表存储着所有到达某一单词的所有路径,队列中只存储着单词这个对象。
这此时不会产生多于的寻路。
class Solution {
public:
bool istransfered(string a,string b){
int len=a.length();
int count=0;
// cout<<a<<" "<<b<<endl;
for(int i=0;i<len;i++){
if(a[i]!=b[i]){
if(count>0)
return false;
count++;
}
}
return true;
}
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
queue<string> q;
unordered_map<string,vector<vector<string>>>mq;
vector<vector<string>>res;
unordered_map<string,int> m;
int length=start.size();
m[start]=0;
auto it=dict.find(end);
if(it!=dict.end()){
dict.erase(it);
}
it=dict.find(start);
if(it!=dict.end()){
dict.erase(it);
}
// dict.insert(end);
q.push(start);
mq[start].push_back(vector<string>(1,start));
bool hasfind=false;
int step;
while(!q.empty()){
string cur=q.front();
vector<vector<string>> &paths=mq[cur];
q.pop();
if(hasfind){
if(paths[0].size()>=step)
continue;
}
if(istransfered(cur,end)){
//std::cout<<cur<<" "<<end<<" size"<<paths[0].size()<<std::endl;
if(!hasfind){
for(int i=0;i<paths.size();i++){
paths[i].push_back(end);
res.push_back(paths[i]);
}
hasfind=true;
step=paths[0].size();
}
else{
if(paths[0].size()>=step){
continue;
}
for(int i=0;i<paths.size();i++){
paths[i].push_back(end);
res.push_back(paths[i]);
}
if(paths[0].size()<step){
return res;
}
}
continue;
}
auto iter=dict.begin();
//vector<vector<string >> &paths=mq[cur];
string curword=cur;
for(int i=0;i<length;i++){
for(char c='a';c<='z';c++){
if(cur[i]==c){
continue;
}
curword[i]=c;
auto iter=dict.find(curword);
if(iter!=dict.end()){
auto iit=m.find(curword);
if(iit!=m.end()){
if(m[curword]<paths[0].size()){
continue;
}
}
else{q.push(*iter);}
//cout<<cur<<" "<<*iter<<endl;
//cout<<paths.size()<<endl;
m[*iter]=paths[0].size();
for(int i=0;i<paths.size();i++){
paths[i].push_back(*iter);
mq[*iter].push_back(paths[i]);
paths[i].pop_back();
}
}
}
curword[i]=cur[i];
}
}
return res;
}
};