Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) 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"]
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.
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
// IMPORTANT: Please reset any member data you declared, as
// the same Solution instance will be reused for each test case.
vector<vector<string>> res;
if(start.size() != end.size()) return res;
if(start.empty() || end.empty())return res;
dict.insert(start);
dict.insert(end);
unordered_map<string,vector<string>> dictmp;
set<string> visited;visited.clear();
vector<string> path;//queue<string> path;
path.push_back(start);//path.push(start);
int count = 1;
//dict.erase(start);
bool found = false;
while(dict.size() > 0 && !path.empty())
{
string curword = path.front();
path.erase(path.begin());//path.pop();
count--;
visited.insert(curword);
if(curword==end) {found = true;}
for(int i = 0; i < curword.size(); i++)
{
string tmp = curword;
for(char j='a'; j<='z'; j++)
{
if(curword[i]==j)continue;
tmp[i] = j;
if(dict.find(tmp) != dict.end() && visited.find(tmp) == visited.end())
{
path.push_back(tmp);//path.push(tmp);
dictmp[curword].push_back(tmp);
}
}
}
if(count==0)
{
if(found)break;
count = path.size();
set<string>::iterator it=visited.begin();
for(;it!=visited.end();it++)
dict.erase(*it);
visited.clear();
for(int i =0; i < count; i++)
visited.insert(path[i]);
}
}
if(dictmp.size() == 0)return res;
//Ladder
vector<string> t;
t.push_back(start);
res.push_back(t);
while(true)
{
vector<vector<string>>::iterator it = res.begin();
string curword = (*it)[(*it).size()-1];
while(it != res.end() && curword == end)
{
it++;
if(it != res.end())
curword = (*it)[(*it).size()-1];
else
break;
}
if(it == res.end())break;
vector<string> tmp = *it;
res.erase(it);
vector<string> sec = dictmp[curword];
for(int i=0; i<sec.size(); i++)
{
if(i!=0)
tmp.pop_back();
tmp.push_back(sec[i]);
res.push_back(tmp);
}
}
return res;
}
使用了一个前驱单词表,即记录每一个单词的前驱单词是哪些。这样在遍历完毕后,我们从end出发递归就能把所有路径生成出来。但是由于前驱单词表不能记录当前的层次信息,似乎我们没法完成去重的工作。这个方案的巧妙之处就在于它没有使用我们通常的队列保存待处理的单词,一个单词一个单词先进先出处理的方法,而是使用两个vector来模拟队列的操作。我们从vector 1中遍历单词进行转换尝试,发现能转换的单词后将其放入vector 2中。当vector 1中的单词处理完毕后即为一层处理完毕,它里面的单词就可以从字典里删去了。接着我们对vector 2进行同样处理,如此反复直到当前处理的vector中不再有单词。我们发现vector 1和vector 2在不断地交换正处理容器和待处理容器的身份,因此可以通过将其放入一个数组中,每次循环对数组下标值取反实现身份的交替.
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)
{
current = !current;
previous = !previous;
for (auto iter = candidates[previous].begin(); iter != candidates[previous].end(); ++iter)
dict.erase(*iter);
candidates[current].clear();
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);
}
}
}
}
if (candidates[current].size() == 0)
return result_;
if (candidates[current].count(end)) break;
}
vector<string> path;
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)
{
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_;
};
http://blog.csdn.net/niaokedaoren/article/details/8884938
http://www.cnblogs.com/shawnhue/archive/2013/06/05/leetcode_126.html