127. 单词接龙
给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:
每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:
如果不存在这样的转换序列,返回 0。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:
输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
输出: 5
解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog",
返回它的长度 5。
示例 2:
输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
输出: 0
解释: endWord "cog" 不在字典中,所以无法进行转换。
解题
将wordlist的每一种变法存在map中:map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
;
begin入队后将map中begin的可变化字符串挨个入队:
for(int i=0;i<beginWord.size();i++){ //map里的三个都进去了
for(auto t:map[beginWord.substr(0,i)+"*"+beginWord.substr(i+1)])
Q.push(t);
map.erase(beginWord.substr(0,i)+"*"+beginWord.substr(i+1));
并删除map中的该key;
找到endword则输出res,否则输出0;
单向BFS
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//预处理,把单词放入*中
for(string s:wordList){
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
}
res=0;
queue<string> Q;
Q.push(beginword);
//cout<<Q.front();
while(!Q.empty()){
++res;
int size=Q.size();
while(size--){
string tmp=Q.front();
Q.pop();
if(tmp==endWord) return res;
for(int i=0;i<tmp.size();i++){ //map里的三个都进去了
for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
Q.push(t);
map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
}
}
}
return 0;
}
private:
int res;
unordered_map<string,vector<string>> map;
};
双向BFS
存储beginword一路变化过来的字符串到res1;
存储endword一路变化过来的字符串到res2;
若beginword正在变化的字符串在res2中出现过,返回当前res;
若endword正在变化的字符串在res1中出现过,返回当前res;
注意点
首先判断wordlist中有无endword,没有则直接返回0;
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
//预处理,把单词放入*中
bool flag=0;
for(string s:wordList){
if(s==endWord) flag=1;
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
}
if(!flag) return 0;
result=0;
queue<string> Q;
queue<string> Q2;
Q.push(beginWord);
Q2.push(endWord);
//反向查找
while(!Q.empty()||!Q2.empty()){
int size=Q.size();
while(size--){
string tmp=Q.front();
if(res2[tmp]) return result;
res1[tmp]=1;
Q.pop();
for(int i=0;i<tmp.size();i++){ //map里的三个都进去了
for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
Q.push(t);
map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
}
}
++result;
size=Q2.size();
while(size--){
string tmp=Q2.front();
if(res1[tmp]) return result;
res2[tmp]=1;
Q2.pop();
for(int i=0;i<tmp.size();i++){ //map里的三个都进去了
for(auto t:map[tmp.substr(0,i)+"*"+tmp.substr(i+1)])
Q2.push(t);
map.erase(tmp.substr(0,i)+"*"+tmp.substr(i+1));
}
}
++result;
}
return 0;
}
private:
int result;
unordered_map<string,vector<string>> map;
unordered_map<string,bool> res1;
unordered_map<string,bool> res2;
};
126. 单词接龙 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” 不在字典中,所以不存在符合要求的转换序列。
解题
上题字典优化的基础上再优化四步:
(1)BFS找最短距离
(2)BFS建立字典树
(3)BFS过程中找到每个单词的最短变化步数
(4)dfs时超过最短距离剪枝;curword超过该单词的最短步数剪枝;直接遍历字典树dfs更快;
BFS找最短距离,DFS找路径;
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
for(auto s:wordList)
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
queue<string> Q;
mincnt=-1;
Q.push(beginWord);
visited[beginWord]=1;
bool flag=0;
while(!Q.empty()){
mincnt++;
int size=Q.size();
while(size--){
string T=Q.front();
Q.pop();
if(T==endWord) {
flag=1;
break;
}
for(int i=0;i<T.size();i++)
for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)])
if(!visited[s]){
visited[s]=1;
Q.push(s);
}
}
if(flag) break;
}
visited.clear();
dfs(beginWord,endWord,0);
return res;
}
private:
unordered_map<string,vector<string>> map;
vector<string> tmp;
vector<vector<string>> res;
unordered_map<string,bool> visited;
int mincnt;
void dfs(string curword, string endWord,int cnt){
if(visited[curword]||cnt>mincnt) return;
if(curword==endWord) {
tmp.push_back(curword);
res.push_back(tmp);
tmp.pop_back();
return;
}
visited[curword]=1;
tmp.push_back(curword);
for(int i=0;i<curword.size();i++)
for(auto t:map[curword.substr(0,i)+"*"+curword.substr(i+1)])
dfs(t,endWord,cnt+1);
tmp.pop_back();
visited[curword]=0;
return;
}
};
DFS找路径,并且找最短距离;
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
for(auto s:wordList)
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
mincnt=INT_MAX;
dfs(beginWord,endWord,0);
return res;
}
private:
unordered_map<string,vector<string>> map;
vector<string> tmp;
vector<vector<string>> res;
unordered_map<string,bool> visited;
int mincnt;
void dfs(string curword, string endWord,int cnt){
if(visited[curword]||cnt>mincnt) return; //剪枝1
if(!distance[curword]||distance[curword]>=cnt){ //剪枝2
distance[curword]=cnt;
}
else return;
if(curword==endWord) {
if(cnt<mincnt){
mincnt=cnt;
res.clear();
}
tmp.push_back(curword);
res.push_back(tmp);
tmp.pop_back();
return;
}
visited[curword]=1;
tmp.push_back(curword);
for(int i=0;i<curword.size();i++)
for(auto t:map[curword.substr(0,i)+"*"+curword.substr(i+1)])
dfs(t,endWord,cnt+1);
tmp.pop_back();
visited[curword]=0;
return;
}
};
BFS找最短距离+建立字典树+DFS找路径+DFS路径剪枝
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
for(auto s:wordList)
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
queue<string> Q;
mincnt=-1;
Q.push(beginWord);
visited[beginWord]=1;
mincnt=INT_MAX;
int cnt=-1;
while(!Q.empty()){
cnt++;
int size=Q.size();
while(size--){
string T=Q.front();
Q.pop();
if(T==endWord) {
mincnt=min(mincnt,cnt);
}
for(int i=0;i<T.size();i++)
for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)]){
HASHMAP[T].push_back(s); //建立字典树优化
if(!visited[s]){
visited[s]=1;
Q.push(s);
}
}
}
}
visited.clear();
dfs(beginWord,endWord,0);
return res;
}
private:
unordered_map<string,int> distance;
unordered_map<string,vector<string>> map;
vector<string> tmp;
vector<vector<string>> res;
unordered_map<string,bool> visited;
unordered_map<string,vector<string>> HASHMAP;
int mincnt;
void dfs(string curword, string endWord,int cnt){
if(visited[curword]||cnt>mincnt) return; //剪枝1
if(!distance[curword]||distance[curword]>=cnt){ //剪枝2
distance[curword]=cnt;
}
else return;
if(curword==endWord) {
tmp.push_back(curword);
res.push_back(tmp);
tmp.pop_back();
return;
}
visited[curword]=1;
tmp.push_back(curword);
for(auto t:HASHMAP[curword])
dfs(t,endWord,cnt+1);
tmp.pop_back();
visited[curword]=0;
return;
}
};
通过代码
将路径剪枝distance在bfs过程中完成,即可优化速度,通过所有样例
BFS——找最短距离+建立字典树+找到每个单词的最短变化步数
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
for(auto s:wordList)
for(int i=0;i<s.size();i++)
map[s.substr(0,i)+"*"+s.substr(i+1)].push_back(s);
queue<string> Q;
mincnt=-1;
Q.push(beginWord);
visited[beginWord]=1;
mincnt=INT_MAX;
int cnt=-1;
while(!Q.empty()){
cnt++;
int size=Q.size();
while(size--){
string T=Q.front();
Q.pop();
if(T==endWord) {
mincnt=min(mincnt,cnt);
}
for(int i=0;i<T.size();i++)
for(auto s:map[T.substr(0,i)+"*"+T.substr(i+1)]){
HASHMAP[T].push_back(s); //建立字典树优化
if(!visited[s]){
distance[s]=cnt;
visited[s]=1;
Q.push(s);
}
}
}
}
visited.clear();
dfs(beginWord,endWord,0);
return res;
}
private:
unordered_map<string,int> distance;
unordered_map<string,vector<string>> map;
vector<string> tmp;
vector<vector<string>> res;
unordered_map<string,bool> visited;
unordered_map<string,vector<string>> HASHMAP;
int mincnt;
void dfs(string curword, string endWord,int cnt){
if(visited[curword]||cnt>mincnt) return; //剪枝1
if(distance[curword]<cnt-1) return; //剪枝2
if(curword==endWord) {
tmp.push_back(curword);
res.push_back(tmp);
tmp.pop_back();
return;
}
visited[curword]=1;
tmp.push_back(curword);
for(auto t:HASHMAP[curword])
dfs(t,endWord,cnt+1);
tmp.pop_back();
visited[curword]=0;
return;
}
};