这次,我们主要谈一下leetcode上的word ladder问题,在leetcode上,有两道关于word ladder的问题,一道是求最短的word ladder的长度,另一道则是求所有的最短的word ladder,虽然这两道题很像,但难度系数是不一样的,第二道难度系数要高一点,我们先从简单的看起吧。
第一道题目是这样的:给定两个单词和一个词典,找到从开始单词到结束单词的最短转化路径的长度,转化过程必须满足下列一下条件:
1、一次只能改变一个单词的一个字母
2、每一个中间单词必须要包含在给定的词典中
例如:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
注意:
1、返回0如果未找到转换序列
2、所有的单词长度相同
3、所有的单词只包含小写
思路:这道题从一个单词转化到另一个单词,只需要变化一个字母即可,之后根据其转化的中间单词继续转化,直至找到最终的单词,所以这道题考虑采用BFS的方法来一层一层地遍历,然后我们只需要看最终endword出现在哪一层即可。具体代码如下:
class Solution {
public:
int ladderLength(string beginWord, string endWord, unordered_set<string>& wordList) {
if(beginWord.size()!=endWord.size()||beginWord.size()==0||endWord.size()==0)
return 0;
int count=1,level=1;
bool b=false;
queue<string> path;
string word,newword;
path.push(beginWord);
while(wordList.size()>0&&!path.empty()){
word=path.front();
path.pop();
count--;
for(int i=0;i<word.size();i++){
for(char ch='a';ch<='z';ch++){
newword=word;
newword[i]=ch;
if(newword==word)
continue;
if(newword==endWord){
b=true;
break;
}
if(wordList.find(newword)!=wordList.end()){
path.push(newword);
wordList.erase(newword);
}
}
if(b)break;
}
if(b)break;
if(count==0){
level++;
count=path.size();
}
}
if(b)
return level+1;
else
return 0;
}
};
第一道题还是挺简单的,只需要一层一层地遍历即可,找到目标单词返回level+1即可,但是第二道题就比较难了,它要我们找到从第一个单词转化到第二个单词的所有最短路径,
例子如下:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Return
[ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ]其他条件和第一道题一样。
乍一看,好像也就这么回事,把第一道题的代码稍微改一下,不返回长度了,把所有的从beginword到endword的路径全部存下来不就行了?实际上不是这样的。首先,你这样做不能保证其长度是最小的,另外可能会漏掉一些最短路径。所以我采取的做法是这样的:仍然是用BFS,但是在BFS过程中,通过当前层的单词找下一层的单词前,把当前层的单词从词典中删掉,并且每找到一个单词,通过一个map的数据结构记录其上一个单词,构成从子单词到父单词的集合的映射unordered_map<string,unordered_set<string>> path,最后如果找到了endword,再通过path反向递推,找到所有的最短路径(这里用了递归)。
具体代码如下:
class Solution {
public:
vector<string> temp_path;
vector<vector<string>> res;
void GeneratePath(unordered_map<string,unordered_set<string>>&path,const string& start,const string& end){
temp_path.push_back(start);
if(start==end){
vector<string> ret = temp_path;
reverse(ret.begin(),ret.end());
res.push_back(ret);
return;
}
for(auto it=path[start].begin();it!=path[start].end();++it){
GeneratePath(path,*it,end);
temp_path.pop_back();
}
}
vector<vector<string>> findLadders(string beginWord, string endWord, unordered_set<string> &wordList) {
temp_path.clear();
res.clear();
unordered_set<string> cur;
unordered_set<string> next;
unordered_map<string,unordered_set<string>> path;
unordered_set<string> unvisited=wordList;
if(unvisited.count(beginWord)>0)
unvisited.erase(beginWord);
cur.insert(beginWord);
while(cur.count(endWord)==0&&unvisited.size()>0){
for(auto pcur =cur.begin();pcur!=cur.end();pcur++){
string word = *pcur;
string temp;
for(int i=0;i<beginWord.size();i++){
for(char ch='a';ch<='z';ch++){
temp=word;
temp[i]=ch;
if(temp==word)continue;
if(unvisited.count(temp)>0){
next.insert(temp);
path[temp].insert(word);
}
}
}
}
if(next.empty())break;
for(auto it=next.begin();it!=next.end();it++){
unvisited.erase(*it);
}
cur=next;
next.clear();
}
if(cur.count(endWord)>0)
GeneratePath(path,endWord,beginWord);
return res;
}
};
这道题最后根据递归关系找出所有的最短路径即可。