题目描述;
字典 wordList
中从单词 beginWord
和 endWord
的 转换序列 是一个按下述规格形成的序列:
- 序列中第一个单词是
beginWord
。 - 序列中最后一个单词是
endWord
。 - 每次转换只能改变一个字母。
- 转换过程中的中间单词必须是字典
wordList
中的单词。
给你两个单词 beginWord
和 endWord
和一个字典 wordList
,找到从 beginWord
到 endWord
的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0。
示例 1:
输入:beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]
输出:5
解释:一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。
概念:
双向BFS:
如果使用两个同时进行的广搜可以有效地减少搜索空间。一边从 beginWord 开始,另一边从 endWord 开始。我们每次从两边各扩展一层节点,当发现某一时刻两边都访问过同一顶点时就停止搜索。这就是双向广度优先搜索,它可以可观地减少搜索空间大小,从而提高代码运行效率。
学习知识:
可以将vector中的输入,放入set中,更容易查询
unordered_set<string> ss(wordList.begin(),wordList.end());
题解:
因为有5000个单词,如果两两单词之间找关系,无疑超时,考虑到每个单词最多也就10*25种状态,枚举,不构图。
题源:https://leetcode-cn.com/problems/word-ladder/
代码:
class Solution { public: int ladderLength(string beginWord, string endWord, vector<string>& wordList) { queue<string> Q1,Q2; unordered_map<string,int> mp1; unordered_map<string,int> mp2; int res=0; for(string i : wordList) {mp1[i]=-1; mp2[i]=-1;} if(mp1.find(endWord)==mp1.end() ) return 0; //如果没有结束单词的状态,直接返回0 mp1[beginWord]=1; mp2[endWord]=1; Q1.push(beginWord); Q2.push(endWord); while(!Q1.empty() && !Q2.empty()) { if (Q1.size()>Q2.size()) {Q1.swap(Q2); mp1.swap(mp2); } //优先遍历节点数少的 for(int t=Q1.size();t>0;t--) { string p=Q1.front(); Q1.pop(); for(int i=0;i<p.length();i++) // 必须遍历一整层,才叫双向bfs { for(int j=0;j<26;j++) { char ch='a'+j; if(ch==p[i]) continue; string newp=p; newp[i]=ch; if(mp1.find(newp)==mp1.end() || mp1[newp]>=0) continue; //如果不存在newp中间状态,或者该方向bfs已经访问过,则continue if(mp2.find(newp)!=mp2.end() && mp2[newp]>=0) // 如果该状态在另个方向bfs时已经访问过,结果就出来了 {res=mp1[p]+mp2[newp]; break;} mp1[newp]=mp1[p]+1; // 否则加入队列中 Q1.push(newp); } if(res) break; } if(res) break; } if(res) break; } return res; } };