问题:
给定StartWord和EndWord,在给定的dict中寻找每次值变换一个字母,最终从StartWord能够推移到EndWord的所有最短序列。
Example 1: Input: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"] Output: [ ["hit","hot","dot","dog","cog"], ["hit","hot","lot","log","cog"] ] Example 2: Input: beginWord = "hit" endWord = "cog" wordList = ["hot","dot","dog","lot","log"] Output: [] Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
解法1:
单向BFS找到路径关系:
1.引入队列q,保存每一步的所有展开结果。在每一步的结尾,用q去替换掉目标队列queue
即从queue一次读取,处理,将结果保存至q,再用q去替换掉queue。
2.每一次的处理:
首先从已经处理过得到的新queue中的元素,从dict中删除。(由于得到queue的方法,即是dict中存在,则保存至queue)
然后遍历queue的每一个word,进行以下处理:
对word的每一个字符,进行a~z字母替换,
判断:1,如果==endWord,则标记found找到。同时记录该路径到children图中。
2,如果dict中存在,则加入新queue中(这里是先保存到q,之后在整体和queue替换),同时记录该路径关系到children图中。
构建children图,key:A字符串,value:B字符串,(由A变化一个字符得到多种可能的B)
unordered_map<string,vector<string>> children; children[parent].push_back(child);
再通过children图进行DFS,构建所有path结果数组。
1 vector<string> path={beginWord}; 2 if(found){ 3 getPath(children, beginWord, endWord, path, res); 4 }
DFS 递归函数:
1 void getPath(unordered_map<string,vector<string>>& children, string beginWord, string endWord, vector<string>& path, vector<vector<string>>& res) { 2 if(beginWord==endWord){ 3 res.push_back(path); 4 return; 5 } 6 const auto find = children.find(beginWord); 7 if(find==children.end()) return; 8 for(const string child: find->second){ 9 path.push_back(child); 10 getPath(children, child, endWord, path, res); 11 path.pop_back(); 12 } 13 }
解法2:
diff解法1:
双向 查找路径关系。每次选取size最短的作为对象,进行展开查找。
将解法1中的对象队列queue,改为q1和q2,
若q1短,那么本次将q1看作queue,q2看作endWord,反之亦然。
所做处理皆同方法1,
只有children的构建,由于双向构建,正向处理的情况下,children构建方法同解法1,
反向处理(由endWord向start推)的情况下,parent和child对掉。
要判定是否为正向,则需要引入变量 backward。
代码参考:
解法1:
1 class Solution { 2 public: 3 void getPath(unordered_map<string,vector<string>>& children, const string beginWord, const string endWord, vector<string>& path, vector<vector<string>>& res) { 4 if(beginWord==endWord){ 5 res.push_back(path); 6 return; 7 } 8 auto find=children.find(beginWord); 9 if(find==children.end()) return; 10 for(const string& child:find->second){ 11 path.push_back(child); 12 getPath(children, child, endWord, path, res); 13 path.pop_back(); 14 } 15 } 16 17 vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) { 18 vector<vector<string>> res; 19 unordered_set<string> dict(wordList.begin(), wordList.end()); 20 unordered_set<string> queue={beginWord}, p; 21 unordered_map<string,vector<string>> children; 22 bool found=false; 23 if(dict.count(endWord)==0)return res; 24 while(!queue.empty()&&!found){ 25 for(const string& word: queue){ 26 dict.erase(word); 27 } 28 for(const string& word: queue){ 29 string cur=word; 30 for(int j=0; j<=word.length(); j++){ 31 char ch=cur[j]; 32 for(char i='a'; i<='z'; i++){ 33 cur[j]=i; 34 if(cur==endWord){ 35 found=true; 36 children[word].push_back(cur); 37 }else if(dict.count(cur)&&!found){ 38 p.insert(cur);//下一次待检索 39 children[word].push_back(cur); 40 } 41 } 42 cur[j]=ch; 43 } 44 } 45 swap(queue,p); 46 p.clear(); 47 } 48 vector<string> path={beginWord}; 49 if(found){ 50 getPath(children, beginWord, endWord, path, res); 51 } 52 return res; 53 } 54 };
解法2:
1 class Solution { 2 public: 3 void getPath(unordered_map<string,vector<string>>& children, string beginWord, string endWord, vector<string>& path, vector<vector<string>>& res) { 4 if(beginWord==endWord){ 5 res.push_back(path); 6 return; 7 } 8 const auto find = children.find(beginWord); 9 if(find==children.end()) return; 10 for(const string child: find->second){ 11 path.push_back(child); 12 getPath(children, child, endWord, path, res); 13 path.pop_back(); 14 } 15 } 16 vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) { 17 vector<vector<string>> res; 18 unordered_set<string> dict(wordList.begin(), wordList.end()); 19 unordered_set<string> q1={beginWord}, q2={endWord}; 20 bool backward=false; 21 unordered_map<string,vector<string>> children; 22 bool found=false; 23 if(dict.count(endWord)==0)return res; 24 while(!q1.empty()&&!q2.empty()&&!found){ 25 if(q1.size()>q2.size()){ 26 backward=!backward; 27 swap(q1,q2); 28 } 29 for(const string& word: q1){ 30 dict.erase(word); 31 } 32 for(const string& word: q2){ 33 dict.erase(word); 34 } 35 unordered_set<string> q; 36 for(const string& word: q1){ 37 string cur=word; 38 for(int j=0; j<=word.length(); j++){ 39 char ch=cur[j]; 40 for(char i='a'; i<='z'; i++){ 41 cur[j]=i; 42 if(q2.count(cur)){ 43 found=true; 44 if(!backward){ 45 children[word].push_back(cur); 46 }else{ 47 children[cur].push_back(word); 48 } 49 }else if(dict.count(cur)&&!found){ 50 q.insert(cur);//下一次待检索 51 if(!backward){ 52 children[word].push_back(cur); 53 }else{ 54 children[cur].push_back(word); 55 } 56 } 57 } 58 cur[j]=ch; 59 } 60 } 61 swap(q1,q); 62 q.clear(); 63 } 64 vector<string> path={beginWord}; 65 if(found){ 66 getPath(children, beginWord, endWord, path, res); 67 } 68 return res; 69 } 70 };