http://www.lintcode.com/zh-cn/problem/word-ladder-ii/#
给出两个单词(start和end)和一个字典,找出所有从start到end的最短转换序列
比如:
- 每次只能改变一个字母。
- 变换过程中的中间单词必须在字典中出现。
样例
给出数据如下:
start = "hit"
end = "cog"
dict = ["hot","dot","dog","lot","log"]
返回
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]
注意
- 所有单词具有相同的长度。
- 所有单词都只包含小写字母。
// Solution
//
// 1) Using BSF algorithm build a graph like below
// 2) Using DSF to parse the tree to the transformation path.
//
// For example:
//
// start = "hit"
// end = "cog"
// dict = ["hot","dot","dog","lot","log","dit","hig", "dig"]
//
// +-----+
// +-------------+ hit +--------------+
// | +--+--+ |
// | | |
// +--v--+ +--v--+ +--v--+
// | dit | +-----+ hot +---+ | hig |
// +--+--+ | +-----+ | +--+--+
// | | | |
// | +--v--+ +--v--+ +--v--+
// +----> dot | | lot | | dig |
// +--+--+ +--+--+ +--+--+
// | | |
// +--v--+ +--v--+ |
// +----> dog | | log | |
// | +--+--+ +--+--+ |
// | | | |
// | | +--v--+ | |
// | +--->| cog |<-- + |
// | +-----+ |
// | |
// | |
// +----------------------------------+
class Solution {
public:
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
unordered_map<string, unordered_set<string>> parent = BFS(start, end, dict);
vector<string> path; path.push_back(start);
vector<vector<string>> paths;
DFS(start, end, parent, path, paths);
return paths;
}
private:
unordered_map<string, unordered_set<string>>
BFS(const string &start, const string &end, const unordered_set<string> &dict) {
/* 用于存储BFS形成的图结构 */
unordered_map<string, unordered_set<string>> parent;
/* 模拟图结构的每一层 */
unordered_set<string> level[3];
unordered_set<string> *previousLevel = &level[0];
unordered_set<string> *currentLevel = &level[1];
unordered_set<string> *nextLevel = &level[2];
unordered_set<string> *p = NULL; // 用于交换指针用
currentLevel->insert(start);
/* BFS */
bool flag = false; // 当下一层插入的word中包含end,即退出BFS,因为所求为最短路径
while (flag == false) { // 还未到最后一层
// 用于存储下一层的newWord(如果存在)
nextLevel->clear();
// 处理当前层
for (const auto &word : *currentLevel) { // 当前层中的每一个word
for (int ix = 0; ix < word.size(); ix++) { // 当前单词的每一个letter
string newWord = word;
for (char c = 'a'; c <= 'z'; c++) { // 对当前letter依次进行26个字母的替换
newWord[ix] = c;
// 不在词典中或者之前层已经出现过
if (dict.count(newWord) == 0 || previousLevel->count(newWord) == 1 || currentLevel->count(newWord) == 1) {
continue;
}
if (newWord == end) {
flag = true;
parent[word].insert(newWord);
continue;
}
parent[word].insert(newWord);
nextLevel->insert(newWord);
}
}
}
if (nextLevel->empty()) {
break;
}
p = currentLevel;
currentLevel = nextLevel;
nextLevel = previousLevel;
previousLevel = p;
}
if (flag == false) {
parent.clear();
}
return parent;
}
void DFS(const string &start, const string &end,
unordered_map<string, unordered_set<string>> &parent,
vector<string> &path,
vector<vector<string>> &paths) {
if (parent.find(start) == parent.end()) {
if (start == end) {
paths.push_back(path);
}
return;
}
for (const auto &word : parent[start]) {
path.push_back(word);
DFS(word, end, parent, path, paths);
path.pop_back();
}
}
};