题目地址:
https://leetcode.com/problems/word-ladder-ii/
给定两个单词作为起点和终点,每一步允许从单词中改变某个位置的字母,变为另一个单词。再给定一个单词的列表,问从起点到终点的所有最短路径,要求路径中所有单词都要在列表里(起点不必在,终点必须在)。题目保证所有单词都由小写字母组成。
BFS记录距离 + DFS。如果列表里没有终点那直接返回空列表。接着先从终点单词开始BFS,搜的过程中用哈希表记录路径上每个单词与起点的距离。一旦搜到终点就停止搜索。设从起点到终点的最少步数是 k k k,那么此时哈希表里已经存了所有距离起点 k − 1 k-1 k−1步以内的单词,以及一部分距离 k k k步的单词(距离 k k k步的单词我们只关心终点,虽然别的单词也可能会加进去)。接着我们从起点向终点DFS,一路永远找步数比当前位置少 1 1 1的单词,直到搜到起点(之所以从终点搜,是因为如果从起点搜的话,即使每次搜的都是比自己步数多 1 1 1的单词,但是有可能搜到第 k k k步的时候搜到了别的单词。从终点开始搜的话能保证搜到第 k k k步一定是起点)。代码如下:
class Solution {
public:
vector<vector<string>> findLadders(string beg, string end,
vector<string> &ws) {
vector<vector<string>> res;
unordered_set<string> set;
for (auto &s : ws) set.insert(s);
if (!set.count(end)) return res;
set.insert(beg);
unordered_map<string, vector<string>> g;
unordered_map<string, int> dist;
dist[end] = 0;
queue<string> q;
q.push(end);
while (q.size()) {
auto s = q.front();
q.pop();
auto t = s;
for (int i = 0; i < s.size(); i++) {
char old = s[i];
for (char ch = 'a'; ch <= 'z'; ch++) {
if (ch == old) continue;
s[i] = ch;
if (set.count(s))
if (!dist.count(s) || dist[s] == dist[t] + 1) {
g[s].push_back(t);
if (!dist.count(s)) q.push(s);
dist[s] = dist[t] + 1;
if (s == beg) break;
}
}
s[i] = old;
}
}
if (!dist.count(beg)) return res;
vector<string> v;
dfs(beg, dist, v, res, g);
return res;
}
void dfs(string s, unordered_map<string, int> &dist, vector<string> &v,
vector<vector<string>> &res,
unordered_map<string, vector<string>> &g) {
v.push_back(s);
if (!dist[s]) {
res.push_back(v);
v.pop_back();
return;
}
for (auto ne : g[s]) dfs(ne, dist, v, res, g);
v.pop_back();
}
};
时间复杂度 O ( n l 2 ) O(nl^2) O(nl2), l l l是单词长度,空间 O ( n l ) O(nl) O(nl)。