题目描述:
给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:
每次转换只能改变一个字母。
转换后得到的单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = “hit”,
endWord = “cog”,
wordList = [“hot”,“dot”,“dog”,“lot”,“log”,“cog”]
输出:
[
[“hit”,“hot”,“dot”,“dog”,“cog”],
[“hit”,“hot”,“lot”,“log”,“cog”]
]
示例 2:
输入:
beginWord = “hit”
endWord = “cog”
wordList = [“hot”,“dot”,“dog”,“lot”,“log”]
输出: []
解释: endWord “cog” 不在字典中,所以不存在符合要求的转换序列。
方法1:
主要思路:
(1)最短路径,可以考虑使用广度优先搜索,剩下的就是建图;
(2)将邻接的双向图,则遍历给出的字典,将可以相邻转换的字符串使用对应的索引建立邻接图,这里需要定义一个判断两个字符串是否是可以相互转换的函数;
(3)在建立邻接图前,先对字典进行判断,主要判断两点,一个是是否包含终止字符串,若不包含,则直接返回空结果,另一个是是否包含开始字符串,若不包含,则需要将开始字符串插入到字典中;
class Solution {
public:
//判断两个字符串是否可以相互转换
bool transform_check(string& str1,string& str2){
int diff=0;
for(int i=0;i<str1.size()&&diff<2;++i){
if(str1[i]!=str2[i]){
++diff;
}
}
return diff==1;
}
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
//起始字符串和终止字符串对应的索引初始化为-1,判断两个字符串在字典中的存在性
int begin_id=-1;
int end_id=-1;
//判断存在性
for(int i=0;i<wordList.size();++i){
if(begin_id==-1&&beginWord==wordList[i]){
begin_id=i;
}
else if(end_id==-1&&endWord==wordList[i]){
end_id=i;
}
}
//若终止字符串不存在字典中,则直接返回空结果
if(end_id==-1){
return {};
}
//若起始字符串不存在字典中,则将起始字符串插入到字典中
if(begin_id==-1){
begin_id=wordList.size();
wordList.push_back(beginWord);
}
//建立邻接图
vector<vector<int>> edges(wordList.size());
//对字典中的字符串进行两两判断
for(int i=0;i<wordList.size();++i){
for(int j=i+1;j<wordList.size();++j){
//若两个字符串满足转换的要求,则插入到邻接图中
if(transform_check(wordList[i],wordList[j])){
edges[i].push_back(j);
edges[j].push_back(i);
}
}
}
vector<vector<string>>res;//存储结果
queue<vector<int>> q;//广度优先的队列
vector<int> costs(wordList.size(),INT_MAX);//用于判断当前的转换路径能否插入到队列中的辅助数组
q.push(vector<int>(1,begin_id));//初始化,从起始字符串开始
costs[begin_id]=0;//初始化
while(!q.empty()){//队列为空,作为终止条件
//找出当前需要判断的路径
vector<int> cur_path=q.front();
q.pop();//弹出
//找出当前路径的最后一个字符串对应的索引位置
int last_id=cur_path.back();
//若当前位置已经是终止位置,则将当前转换路径存入到结果中
if(last_id==end_id){
//将索引形式的转换路径, 变化为字符串形式的转换路径
vector<string> tmp;
tmp.reserve(cur_path.size());
for(int&id: cur_path){
tmp.push_back(wordList[id]);
}
//将转换路径压入到结果
res.push_back(tmp);
}
else{
//遍历邻接图
for(int i=0;i<edges[last_id].size();++i){
int to=edges[last_id][i];
//若邻接图中的邻接字符串对应的位置,可以满足路径的“长度要求”,则压入到队列中
if(costs[last_id]+1<=costs[to]){
costs[to]=costs[last_id]+1;//更新长度
vector<int> tmp(cur_path);//新的路径
tmp.push_back(to);//尾结点放入到新的路径中
q.push(tmp);//将新的路径压入到队列中
}
}
}
}
return res;//返回结果
}
};