题目描述:
Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord toendWord, such that:
- Only one letter can be changed at a time
- Each intermediate word must exist in the word list
For example,
Given:
beginWord = "hit"
endWord = "cog"
wordList = ["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.
首先按照宽度优先建立从字符串start每次变化一个字符直到字符串end的图,
然后从start到end的所有路径即为所求的结果。
在宽度优先建立从字符串start每次变化一个字符直到字符串end的图的过程使用两个集合,
分别保存当前阶段和下一阶段的字符串的集合。对于当前阶段的字符串集合的处理包括两个步骤:
(1)对于当前阶段的字符串集合首先把它们从输入字符串字典中删除
(2)下一阶段的字符串的集合由当前阶段的字符串集合中的字符串变化一个字符得到。
当前阶段的字符串集合初始化只包含start字符串。
AC代码如下:
class Solution {
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict)
{
result_.clear();
unordered_map<string, vector<string>> prevMap;
for (auto iter = dict.begin(); iter != dict.end(); ++iter)
prevMap[*iter] = vector<string>();
vector<unordered_set<string>> candidates(2); //当前阶段和下一阶段字符串集合
int current = 0;
int previous = 1;
candidates[current].insert(start);
while (true)
{//宽度优先建立从字符串start每次变化一个字符直到字符串end的图
current = !current;
previous = !previous;
//1.从输入字符串字典中删除当前阶段的字符串
for (auto iter = candidates[previous].begin(); iter != candidates[previous].end(); ++iter)
dict.erase(*iter);
candidates[current].clear();
//2.下一阶段的字符串的集合由当前阶段的字符串集合中的字符串变化一个字符得到
for (auto iter = candidates[previous].begin(); iter != candidates[previous].end(); ++iter)
{
for (size_t pos = 0; pos < iter->size(); ++pos)
{
string word = *iter;
for (int i = 'a'; i <= 'z'; ++i)
{
if (word[pos] == i)continue;
word[pos] = i;
if (dict.count(word) > 0)
{
prevMap[word].push_back(*iter);
candidates[current].insert(word);
}
}
}
}
//如果下一阶段的字符串集合为空,即无法建立从start到end的图
if (candidates[current].size() == 0)
return result_;
//如果已经到达字符串end,则建图过程结束
if (candidates[current].count(end)) break;
}
vector<string> path;
//深度优先遍历找到从字符串start到字符串end的路径
GeneratePath(prevMap, path, end);
return result_;
}
private:
void GeneratePath(unordered_map<string, vector<string>> &prevMap, vector<string>& path, const string& word)
{
if (prevMap[word].size() == 0) //ie. reach the start word
{
path.push_back(word);
vector<string> curPath = path;
reverse(curPath.begin(), curPath.end());
result_.push_back(curPath);
path.pop_back();
return;
}
path.push_back(word);
for (auto iter = prevMap[word].begin(); iter != prevMap[word].end(); ++iter)
GeneratePath(prevMap, path, *iter);
path.pop_back();
}
vector<vector<string>> result_;
};