LeetCode | Word Ladder II
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:
Only one letter can be changed at a time
Each intermediate word must exist in the dictionary
For example,
Given:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
Return
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
Note:
All words have the same length.
All words contain only lowercase alphabetic characters.
从Word Ladder 这道题我们大概知道怎么做了。先用BFS遍历到end,顺便记录下每个节点的前置节点。最后用dfs把整条路径给输出来。
Word Ladder 中有两种方法,用方法一保存前置节点不知道为什么总会Memory Limit Exceeds.
后来仔细一想,其实和Word Ladder 中提到的bug一样,同层的点可能也是邻居(只差一个字符),那么一个点就会重复地被加入到queue里面,导致了pres数组增大。
用第二种方法就AC了。
1 class Solution { 2 public: 3 int ladderLength(string start, string end, unordered_set<string> &dict) { 4 if (dict.empty()) return 0; 5 if (start.empty() || end.empty()) return 0; 6 if (start.length() != end.length()) return 0; 7 dict.insert(end); 8 9 vector<unordered_set<string> > layers(2); 10 int cur = 0, pre = 1; 11 layers[pre].insert(start); 12 dict.erase(start); 13 14 int n = start.length(); 15 16 int h = 1; 17 bool found = false; 18 while (!layers[pre].empty()) { 19 for (unordered_set<string>::iterator it = layers[pre].begin(); it != layers[pre].end(); ++it) { 20 dict.erase(*it); 21 } 22 layers[cur].clear(); 23 for (unordered_set<string>::iterator it = layers[pre].begin(); it != layers[pre].end(); ++it) { 24 for (int i = 0; i < n; ++i) { 25 string next(*it); 26 for (char c = 'a'; c <= 'z'; ++c) { 27 if ((*it)[i] == c) continue; 28 next[i] = c; 29 30 if (dict.count(next) > 0) { 31 if (next == end) found = true; 32 pres[next].push_back(*it); 33 34 layers[cur].insert(next); 35 } 36 } 37 } 38 } 39 40 cur = !cur; 41 pre = !pre; 42 h++; 43 if (found) return h; 44 } 45 46 return 0; 47 } 48 49 vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) { 50 int min = ladderLength(start, end, dict); 51 if (min == 0) return rets; 52 53 vector<string> ret; 54 build(start, end, ret); 55 return rets; 56 } 57 58 void build(string &start, string end, vector<string> &ret) { 59 if (end == start) { 60 ret.insert(ret.begin(), start); 61 rets.push_back(ret); 62 ret.erase(ret.begin()); 63 return; 64 } 65 66 ret.insert(ret.begin(), end); 67 for (vector<string>::iterator it = pres[end].begin(); it != pres[end].end(); ++it) { 68 build(start, *it, ret); 69 } 70 ret.erase(ret.begin()); 71 } 72 73 private: 74 unordered_map<string, vector<string> > pres; 75 vector<vector<string> > rets; 76 };
第三次刷,用了一个map使得每一层的string都惟一,去重。还有在build的时候,先反序地生成,最终再reverse过来,因为vector的头部插入的开销还是蛮大的。
AC, 664ms,相当快了。
1 class Solution { 2 public: 3 bool findPath(string start, string end, unordered_set<string> &dict, unordered_map<string, vector<string> > &prev) { 4 vector<vector<string> > layers(2); 5 int cur = 0, next = 1, n = 1; 6 layers[cur].push_back(start); 7 dict.insert(end); 8 9 bool flag = false; 10 while (!layers[cur].empty()) { 11 layers[next].clear(); 12 for (auto str: layers[cur]) { 13 dict.erase(str); 14 } 15 unordered_map<string, bool> contained; 16 17 for (auto str: layers[cur]) { 18 if (str == end) break; 19 for (int i = 0; i < str.length(); i++) { 20 string tmp(str); 21 for (char c = 'a'; c <= 'z'; c++) { 22 if (str[i] == c) continue; 23 tmp[i] = c; 24 if (dict.count(tmp) > 0) { 25 if (tmp == end) { 26 flag = true; 27 } 28 if (contained.count(tmp) == 0) layers[next].push_back(tmp); 29 contained[tmp] = true; 30 prev[tmp].push_back(str); 31 } 32 } 33 } 34 } 35 if (flag) break; 36 cur = !cur; next = !next; 37 } 38 39 return flag; 40 } 41 42 void build(string start, string end, vector<vector<string> > &ans, 43 unordered_map<string, vector<string> > &prev, vector<string> &ret) { 44 ret.push_back(end); 45 if (end == start) { 46 ans.push_back(ret); 47 } else { 48 for (auto str: prev[end]) { 49 build(start, str, ans, prev, ret); 50 } 51 } 52 ret.pop_back(); 53 } 54 55 void reverse(vector<string> &path) { 56 for (int i = 0, j = path.size() - 1; i < j; i++, j--) swap(path[i], path[j]); 57 } 58 59 vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) { 60 vector<vector<string> > ans; 61 unordered_map<string, vector<string> > prev; 62 63 if (!findPath(start, end, dict, prev)) return ans; 64 65 vector<string> ret; 66 build(start, end, ans, prev, ret); 67 68 for (auto it = ans.begin(); it != ans.end(); it++) { 69 reverse(*it); 70 } 71 return ans; 72 } 73 };