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.
一:floyd O(N^3)
class Solution {
public:
int ladderLength(string start, string end, unordered_set<string> &dict) {
dict_vec.assign(dict.begin(), dict.end());
dict_vec.insert(dict_vec.begin(), start);
dict_vec.push_back(end);
int n = dict_vec.size();
f = vector<vector<int> > (n, vector<int> (n, -1));
for(int i = 0; i < n; ++i){
f[i][i] = 0;
for(int j = i + 1; j < n; ++j){
if(check(dict_vec, i, j)){
f[i][j] = 1;
f[j][i] = 1;
}
}
}
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
for(int k = 0; k < n; ++k){
if(f[i][k] > -1 && f[k][j] > -1)
if(f[i][j] == -1 || f[i][j] > f[i][k] + f[k][j]){
f[i][j] = f[i][k] + f[j][k];
f[j][i] = f[i][j];
}
}
return f[0][n - 1] + 1;
}
private:
vector<string> dict_vec;
vector<vector<int> > f;
bool check(vector<string> &dict, int i, int j){
int diff = 0;
for(unsigned int k = 0; k < dict[i].length(); ++k){
if(dict[i][k] != dict[j][k])
if((++diff) > 1)
return false;
}
return diff == 1;
}
};
二. dijkstra O(N^2)
class Solution {
public:
int ladderLength(string start, string end, unordered_set<string> &dict) {
dict_vec.assign(dict.begin(), dict.end());
dict_vec.insert(dict_vec.begin(), start);
dict_vec.push_back(end);
int n = dict_vec.size();
f = vector<vector<int> > (n, vector<int> (n, -1));
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j){
f[i][j] = check(dict_vec, i ,j);
f[j][i] = f[i][j];
}
vector<int> dis(n, -1);
vector<bool> visited(n, false);
for(int i = 0; i < n; ++i){
dis[i] = f[0][i];
}
visited[0] = true;
for(int l = 1; l <= n - 1; ++l){
if(visited[n - 1]){
break;
}
int minn = 2147483647;
int mini = -1;
for(int i = 0; i < n; ++i){
if(!visited[i] && dis[i] != -1 && minn > dis[i]){
minn = dis[i];
mini = i;
}
}
if(minn == 2147483647) return 0;
visited[mini] = true;
for(int i = 0; i < n; ++i){
if(!visited[i] && f[i][mini] != -1)
if(dis[i] == -1 || dis[i] > minn + f[i][mini]){
dis[i] = minn + f[i][mini];
}
}
}
return dis[n - 1] + 1;
}
private:
vector<string> dict_vec;
vector<vector<int> > f;
int check(vector<string> &dict, int i, int j){
int diff = 0;
for(unsigned int k = 0; k < dict[i].length(); ++k){
if(dict[i][k] != dict[j][k])
if((++diff) > 1)
return -1;
}
return diff;
}
};
3.spfa
class Solution {
public:
int ladderLength(string start, string end, unordered_set<string> &dict) {
dict_vec.assign(dict.begin(), dict.end());
dict_vec.insert(dict_vec.begin(), start);
dict_vec.push_back(end);
int n = dict_vec.size();
f = vector<vector<int> > (n, vector<int> (n, -1));
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j){
f[i][j] = check(dict_vec, i ,j);
f[j][i] = f[i][j];
}
vector<int> dis(n, -1);
queue<int> Q;
vector<bool> inQ(n, false);
dis[0] = 0;
Q.push(0);
inQ[0] = true;
while(!Q.empty()){
int head = Q.front();
Q.pop();
for(int i = 0; i < n; ++i){
if(!inQ[i] && f[head][i] != -1)
if(dis[i] == -1 || dis[i] > dis[head] + f[head][i]){
Q.push(i);
inQ[i] = true;
dis[i] = dis[head] + f[head][i];
}
}
inQ[head] = false;
}
return dis[n - 1] + 1;
}
private:
vector<string> dict_vec;
vector<vector<int> > f;
int check(vector<string> &dict, int i, int j){
int diff = 0;
for(unsigned int k = 0; k < dict[i].length(); ++k){
if(dict[i][k] != dict[j][k])
if((++diff) > 1)
return -1;
}
return diff;
}
};
嗯,以上算法没有一个能过的,不是超时就是超内存
因为此题不适合直接使用最短路,因为一般只要能到就是最优的,如果要构造邻接矩阵就要O(N^2)。
可以采用一个一个字符替换尝试的方法,这样复杂度就是O(26*L*N) = O(N)
class Solution {
public:
int ladderLength(string start, string end, unordered_set<string> &dict) {
int n = dict.size();
queue<string> Q;
queue<int> disQ;
unordered_map<string, bool> M;
Q.push(start);
disQ.push(0);
M[start] = true;
while(!Q.empty()){
string head = Q.front();
Q.pop();
int headDis = disQ.front();
disQ.pop();
for(unsigned int l = 0; l < head.length(); ++l){
string str = head;
for(char ch = 'a'; ch <= 'z' ; ++ch)
if(ch != str[l]){
str[l] = ch;
if(str == end){
return headDis + 1 + 1;
}
if(dict.find(str) != dict.end() && M.find(str) == M.end()){
Q.push(str);
disQ.push(headDis + 1);
M[str] = true;
cout << str << ":" << headDis + 1 << endl;
}
}
}
}
return 0;
}
private:
};