Word Ladder
Given two words (start and end), and a dictionary, find the length of shortest transformation sequence 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"]
As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog"
,
return its length 5
.
Note:
- Return 0 if there is no such transformation sequence.
- All words have the same length.
- All words contain only lowercase alphabetic characters.
这道题数据规模dict.size() 最大4000+。
构建图(每两个可转换的单词连一条边)以后,bfs一边。
本身不难,不过非常容易超时。主要构建图是如果用N*N来搞的话,会超时。
加速1:
因此构建图可以采用别的方法:在找“hot”相邻的词时,可以改变hot中一个字符,例如“aot”,然后在dict里面找是否有。
这样的复杂度为O(N+N*logN*26*LEN), len为单词平均长度
只要26×len×LogN < N。那么就加速了。
加速2:
另外,其实构建图时,可以推迟构建全图。
每次要用到与某个词相邻的词时,再构建。这样会快点。
class Solution { public: bool cmp(const string& a, const string& b) { if (a.size() != b.size()) return false; bool flag = false; for (int i = 0; i < a.size(); ++i) { if (a[i] != b[i]){ if (flag == false) flag = true; else return false; } } return flag; } void getNext(const string& tmp, const unordered_set<string>& dict, vector<string> &v ) { for (int i = 0; i < tmp.size(); ++i) { for (int j = 0; j < 26; ++j) { if (tmp[i] == 'a' + j) continue; string t2 = tmp; t2[i] = 'a' + j; auto res = dict.find(t2); if (res != dict.end()){ v.push_back(t2); } } } } int ladderLength(string start, string end, unordered_set<string> &dict) { int dsize = dict.size(); queue<string> q; queue<int > l; unordered_set<string> visited; auto it = dict.find(start); if (it != dict.end()) { q.push(*it); visited.insert(*it); l.push(1); } else { for (auto i = dict.begin(); i != dict.end(); ++i) { if (cmp(start, *i)) { q.push(*i); visited.insert(*i); l.push(2); } } } int level; while (!q.empty()) { string cur = q.front(); q.pop(); level = l.front(); l.pop(); vector<string> v; getNext(cur, dict, v); for (int i = 0; i < v.size(); ++i) { if (v[i] == end) return level + 1; } for (int i = 0; i < v.size(); ++i) { if (visited.count(v[i]) == 0) { if (cmp(v[i], end)) return level + 2; else { q.push(v[i]); l.push(level + 1); visited.insert(v[i]); } } } } return 0; } };
class Solution { public: int ladderLength(string start, string end, unordered_set<string> &dict) { if (start == end) return 1; unordered_map<string, int> id; vector<string> str; int idx = 0; for (auto it = dict.begin(); it != dict.end(); ++it) { if (id.count(*it) > 0) continue; id[*it] = idx++; str.push_back(*it); } if (id.count(end) == 0) id[end] = idx++, str.push_back(end); int endid = id[end]; vector<bool> vis(idx, false); queue<int> q; int level = 2; vector<int> next; getnext(id, start, vis, next); if (vis[endid]) return level; while (!next.empty()) { vector<int> cur(next); next.clear(); for (int i = 0; i < cur.size(); i++) { getnext(id, str[cur[i]], vis, next); if (vis[endid]) return level+1; } level++; } return 0; } void getnext(const unordered_map<string,int> &id, string& a, vector<bool>& vis, vector<int> & res) { int len = a.size(); for (int i = 0; i < len; i++) { char c = a[i]; for (char t = 'a'; t < 'z'; t++) { if (t == c) continue; a[i] = t; auto it = id.find(a); if (it != id.end() && vis[it->second] == false) { vis[it->second] = true; res.push_back(it->second); } } a[i] = c; } } };