- 单词接龙 II
给定两个单词(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” 不在字典中,所以不存在符合要求的转换序列。
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<unordered_set>
#include<queue>
#include<unordered_map>
using namespace std;
思路是:
bfs,难点在于如何保存路径,在于如何建图,思路在代码的注释中
class Solution {
public:
//邻接表的图
vector<vector<string>> G;
unordered_set <string> set;
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
//结果保存
vector<vector<string>> res;
//哈希表用O(1)的时间查找某个元素是否在表里
for (string word : wordList)
{
set.insert(word);
}
//beginWord可能不在wordList,不在的话,就添加进去
if (!set.count(beginWord))
{
wordList.insert(wordList.begin(), beginWord);
set.insert(beginWord);
}
//邻接表表示图,初始化大小
G.resize(wordList.size());
//如果endword不在数组里面就结束了
if (wordList.size() == 0 || !set.count(endWord)){
return res;
}
//每个单词的长度
int wordLen = beginWord.length();
//用来判断是否被访问过
unordered_map<string, bool> visited;
//哈希表映射,用string,映射除在数组中的下标
unordered_map<string, int> pos;
for (int i = 0; i < wordList.size(); i++)
{
isConnected(i, wordList); /*建树*/
visited[wordList[i]] = false; //标注未访问
pos[wordList[i]] = i; //吧数组元素放入哈希表中
}
visited[beginWord] = true;
//用bfs遍历图需要队列,队列中存储的是路径
queue<vector<string>> q;
//第一条路径
vector<string>path;
path.push_back(beginWord);
q.push(path);
int flag = 0;
/*我们需要再每一层都遍历完,再把遍历过的结点标志为true,
如果遍历一个结点就标志,可能这一层有几个结点,都与下一层同一个结点相连.如果标志了,那么就只添加了一条路径,
必须在这一层遍历完之后,再把所有下一层的结点标志为true,下一层的结点保存在visit中*/
vector<string> visit;
while (!q.empty())
{
int current_size = q.size();
if (flag) break;
visit.clear();
//一层一层遍历,循环结束就是遍历了一层并且吧下一层的结点添加到队列中
for (int i = 0; i < current_size; i++)
{
//弹出一条路径
vector<string> now = q.front(); q.pop();
//获取路径上的最后一个结点
string last = now.back();
//通过映射获取下标
int cur = pos[last];
for (string& s : G[cur])
{
//如果下一层的结点是终点,添加到路径上,然后添加到结果中
if (s == endWord){
vector<string> tmp(now);
tmp.push_back(s);
res.push_back(tmp);
flag = 1;
}
else if (!visited[s]){
//如果没有被访问,就添加到路径中
vector<string> tmp(now);
tmp.push_back(s);
visit.push_back(s);
q.push(tmp);
}
}
}
//吧下一层的结点标志为访问
for (int i = 0; i < visit.size(); i++)
{
visited[visit[i]] = true;
}
}
return res;
}
void isConnected(int cur ,vector<string>& wordList)
{
//吧与下标为cur的相连的结点,添加到G[cur]的表中
//判断是否相连的方法,就是修改word其中的一个字母然后判断是否在哈希表中
int wordLen = wordList[0].length();
for (int i = 0; i < wordLen; i++)
{
char origin = wordList[cur][i];
for (char c = 'a'; c <= 'z'; c++)
{
if (c == origin) continue;
wordList[cur][i] = c;
if (set.count(wordList[cur])){
G[cur].push_back(wordList[cur]);
}
}
wordList[cur][i] = origin;
}
}
};
int main()
{
string beginWord = "red";
string endWord = "tax";
vector<string> a;
a.push_back("ted");
a.push_back("tex");
a.push_back("red");
a.push_back("tax");
a.push_back("tad");
a.push_back("den");
a.push_back("rex");
a.push_back("pee");
Solution s;
s.findLadders(beginWord, endWord, a);
}