一、题目简述
给定两个单词(beginWord和endWord),和一个单词字典,找到所有从beginWord到endWord的最短转换,使得:
- 每次只能改变一个字母;
- 每个转换单词都必须在单词字典中,注意到,beginWord不是一个转换单词。
例如,
给定:
beginWord=“hit”
endWord=“cog”
wordList=[“hot”,”dot”,”dog”,”lot”,”log”,”cog”]
返回:
[
[“hit”,”hot”,”dot”,”dog”,”cog”],
[“hit”,”hot”,”lot”,”log”,”cog”]
]
注意到:
- 如果不存在满足条件的转换序列,则返回空列表。
- 所有的单词都有相同的长度
- 所有的单词都只包含小写的阿拉伯字符
- 假设列表中没有重复单词
- 假设beginWord和endWord非空,并且不相同
函数原型:
int strDiff(string str1,string str2)
二、编程思路
Word Ladder I&II的思路类似,只是I只需要返回最短转化路径的长度,而II则需要返回所对应的路径。对于类似的最短转化次数的问题,一般都可以采用宽度优先搜索BFS的思路。将beginWord作为搜索起点,endWord为搜索终点。对于WordList列表中的单词,使用下标表示每个字符串,并且使用邻接表记录每个单词能够经过一次转化就得到单词的下标。
由于需要返回相应的路径,因此还需要使用一个队列记录从beginWord转换到当前单词的路径。
为了避免重复的搜索,可以记录每个单词是否被访问过,使用逐层的BFS,对于下一层,都不在访问上一层已经访问过的单词。
三、代码设计
class Solution {
public:
int strDiff(string str1,string str2){
int len=min(str1.length(),str2.length());
int ans=0;
ans+=abs(str1.length()-str2.length());
for(int i=0;i<len;i++){
if(str1[i]!=str2[i]) ans++;
}
return ans;
}
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
int num=wordList.size();
vector<vector<int> >adjList,idx_ans;
vector<vector<string> >str_ans;
//检查endWord是否在wordList中
bool end_flag=true,begin_flag=true;
int end_idx=0,begin_idx=0;
for(int i=0;i<num;i++){
if(strDiff(endWord,wordList[i])==0){
end_flag=false;
end_idx=i;
}
if(strDiff(beginWord,wordList[i])==0){
begin_flag=false;
begin_idx=i;
}
}
if(end_flag) return str_ans;
if(begin_flag){
wordList.insert(wordList.begin(),beginWord);
num++;
end_idx++;
}
//计算每个单词的邻接单词
for(int i=0;i<num;i++){
vector<int> tmp;
for(int j=0;j<num;j++){
if((1==strDiff(wordList[i],wordList[j]))){
tmp.push_back(j);
}
}
adjList.push_back(tmp);
}
//进行广度优先搜索
queue<int> q;
queue<vector<int> >status;
q.push(begin_idx);
status.push(vector<int>(1,begin_idx));
vector<bool> is_visit(num,false);
is_visit[begin_idx]=true;
int min_len=num;
bool end_loop=false;
while(!q.empty()){
int q_size=q.size();
vector<int>visit_idx;
//逐层搜索
for(int i=0;i<q_size;i++){
int cur=q.front(); q.pop();
vector<int> cur_st=status.front(); status.pop();
if(cur_st.size()>min_len){
end_loop=true;
continue;
}
//找到了endWord的情况
if(cur==end_idx){
idx_ans.push_back(cur_st);
min_len=cur_st.size();
end_loop=true;
continue;
}
for(int j=0;j<adjList[cur].size();j++){
if(!is_visit[adjList[cur][j]])
{
vector<int> tmp_st(cur_st);
tmp_st.push_back(adjList[cur][j]);
// cout<<adjList[cur][j]<<" ";
q.push(adjList[cur][j]);
visit_idx.push_back(adjList[cur][j]);
status.push(tmp_st);
}
}
}
for(int j=0;j<visit_idx.size();j++){
is_visit[visit_idx[j]]=true;
}
if(end_loop) break;
}
for(int i=0;i<idx_ans.size();i++){
vector<string> tmp;
for(int j=0;j<idx_ans[i].size();j++){
tmp.push_back(wordList[idx_ans[i][j]]);
}
str_ans.push_back(tmp);
}
return str_ans;
}
};
四、参考资料
使用此种方法,思路简单,但较为耗时。可以参考题解中使用双向BFS缩小算法的时间。
126. Word Ladder II题解