[LeetCode] Word Ladder II
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.
思路转载 http://www.cnblogs.com/TenosDoIt/p/3443512.html
分析:本题主要的框架和上一题是一样,但是还要解决两个额外的问题:一、 怎样保证求得所有的最短路径;二、 怎样构造这些路径
第一问题:
- 不能像上一题第二点注意那样,找到一个单词相邻的单词后就立马把它从字典里删除,因为当前层还有其他单词可能和该单词是相邻的,这也是一条最短路径,比如hot->hog->dog->dig和hot->dot->dog->dig,找到hog的相邻dog后不能立马删除,因为和hog同一层的单词dot的相邻也是dog,两者均是一条最短路径。但是为了避免进入死循环,再hog、dot这一层的单词便利完成后dog还是得从字典中删除。即等到当前层所有单词遍历完后,和他们相邻且在字典中的单词要从字典中删除。
- 如果像上面那样没有立马删除相邻单词,就有可能把同一个单词加入bfs队列中,这样就会有很多的重复计算(比如上面例子提到的dog就会被2次加入队列)。因此我们用一个哈希表来保证加入队列中的单词不会重复,哈希表在每一层遍历完清空(代码中hashtable)。
- 当某一层的某个单词转换可以得到end单词时,表示已经找到一条最短路径,那么该单词的其他转换就可以跳过。并且遍历完这一层以后就可以跳出循环,因为再往下遍历,肯定会超过最短路径长度
第二个问题:
- 为了输出最短路径,我们就要在比bfs的过程中保存好前驱节点,比如单词hog通过一次变换可以得到hot,那么hot的前驱节点就包含hog,每个单词的前驱节点有可能不止一个,那么每个单词就需要一个数组来保存前驱节点。为了快速查找因此我们使用哈希表来保存所有单词的前驱路径,哈希表的key是单词,value是单词数组。(代码中的unordered_map<string,vector<string> >prePath)
- 有了上面的前驱路径,可以从目标单词开始递归的构造所有最短路径(代码中的函数 ConstructResult)
class Solution {
public:
vector<vector<string> > findLadders(string start, string end, unordered_set<string>& dict)
{
vector<vector<string> > result;
if(start.empty() || end.empty() )
return result;
if(start.size() != end.size())
return result;
size_t size = start.size();
unordered_set<string> cur, next;//use set to aviod add duplicate element
unordered_map<string, vector<string> > father;
unordered_set<string> visited; // 判重
cur.insert(start);
bool found = false;
while(!cur.empty() && !found)
{
for (const auto& word : cur)
visited.insert(word);
for(unordered_set<string>::iterator it = cur.begin(); it != cur.end(); it++)
{
string curStr= *it;
//cout << "=========" <<curStr <<"========================" <<endl;
for(int i = ; i< size; i++)
{
for(char j = 'a'; j <= 'z'; j++ )
{
string nextStr = curStr;
if(nextStr[i] == j)
continue;
nextStr[i] = j;
if(nextStr.compare(end) == )
{
//if found, just traverse this layer, not go to next layer
found = true;
father[nextStr].push_back(curStr);
}
#if 0
cout << "nextStr = " << nextStr<< endl;
cout << "nextStr [i] = " << nextStr[i]<< endl;
cout << "i = " << i<< endl;
cout << "j = " << j<< endl;
#endif
//if(dict.find(nextStr) != dict.end() && cur.find(nextStr) == cur.end())
if(dict.find(nextStr) != dict.end() && !visited.count(new_word))
// must add "&& cur.find(nextStr) == cur.end()"
// to avoid the same level 's elemnt point each other
// for example hot --> dot
// hot --> lot
// but when you travel to dot, may happen dot --> lot
// but when you travel to lot, may happen lot --> dot
// so when add it to next, we must confirm that lot is not in this level
{
//cout << "insert\t" << nextStr<< "\tto next queue" << endl;
next.insert(nextStr);
father[nextStr].push_back(curStr);
}
}
}
}
// remove the cur layer's elements form dict
for(unordered_set<string>::iterator it = cur.begin(); it != cur.end(); it++)
{
string tmp = *it;
if(dict.find(tmp) != dict.end())
{
dict.erase(dict.find(tmp));
//cout << "erase \t" << tmp <<endl;
}
}
cur.clear();
swap(cur, next);
}
vector<string> path;
for(unordered_map<string, vector<string> >::iterator it = father.begin(); it != father.end(); it++)
{
string str =(*it).first;
vector<string> vect =(*it).second;
//cout << "map key :" << str <<endl;
for(int i = ; i < vect.size(); i++)
{
//cout << "\tmap value:" << vect[i]<<endl;
}
}
genPath(start, end, path, father, result);
return result;
}
void genPath(string start, string end, vector<string>& path, unordered_map<string, vector<string> >map, vector<vector<string> >& result)
{
path.push_back(end);
if(start == end)
{
reverse(path.begin(), path.end());
result.push_back(path);
//printVector(path);
reverse(path.begin(), path.end());
}
else
{
int size = map[end].size();
for( int i = ; i < size; i++)
{
string str = map[end][i];
genPath(start, str, path, map, result);
}
}
path.pop_back();
}
};
大数据会超时,
转一个网上找的能通过的版本,随后在仔细分析差距在哪里吧。。
class Solution {
public:
vector<vector<string> > findLadders(string start, string end,
const unordered_set<string> &dict) {
unordered_set<string> current, next; // 当前层,下一层,用集合是为了去重
unordered_set<string> visited; // 判重
unordered_map<string, vector<string> > father; // 树
bool found = false;
auto state_is_target = [&](const string &s) {return s == end;};
auto state_extend = [&](const string &s) {
unordered_set<string> result;
for (size_t i = ; i < s.size(); ++i) {
string new_word(s);
for (char c = 'a'; c <= 'z'; c++) {
if (c == new_word[i]) continue;
swap(c, new_word[i]);
if ((dict.count(new_word) > || new_word == end) &&
!visited.count(new_word)) {
result.insert(new_word);
}
swap(c, new_word[i]); // 恢复该单词
}
}
return result;
};
current.insert(start);
while (!current.empty() && !found) {
// 先将本层全部置为已访问,防止同层之间互相指向
for (const auto& word : current)
visited.insert(word);
for (const auto& word : current) {
const auto new_states = state_extend(word);
for (const auto &state : new_states) {
if (state_is_target(state)) found = true;
next.insert(state);
father[state].push_back(word);
// visited.insert(state); // 移动到最上面了
}
}
current.clear();
swap(current, next);
}
vector<vector<string> > result;
if (found) {
vector<string> path;
gen_path(father, path, start, end, result);
}
return result;
}
private:
void gen_path(unordered_map<string, vector<string> > &father,
vector<string> &path, const string &start, const string &word,
vector<vector<string> > &result) {
path.push_back(word);
if (word == start) {
result.push_back(path);
reverse(result.back().begin(), result.back().end());
} else {
for (const auto& f : father[word]) {
gen_path(father, path, start, f, result);
}
}
path.pop_back();
}
};
[LeetCode] Word Ladder II的更多相关文章
- [leetcode]Word Ladder II @ Python
[leetcode]Word Ladder II @ Python 原题地址:http://oj.leetcode.com/problems/word-ladder-ii/ 参考文献:http://b ...
- LeetCode :Word Ladder II My Solution
Word Ladder II Total Accepted: 11755 Total Submissions: 102776My Submissions Given two words (start ...
- LeetCode: Word Ladder II 解题报告
Word Ladder II Given two words (start and end), and a dictionary, find all shortest transformation s ...
- [LeetCode] Word Ladder II 词语阶梯之二
Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...
- LeetCode: Word Ladder II [127]
[题目] Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...
- leetcode—word ladder II
1.题目描述 Given two words (start and end), and a dictionary, find all shortest transformation sequence( ...
- LeetCode:Word Ladder I II
其他LeetCode题目欢迎访问:LeetCode结题报告索引 LeetCode:Word Ladder Given two words (start and end), and a dictiona ...
- [Leetcode Week5]Word Ladder II
Word Ladder II 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder-ii/description/ Descripti ...
- 【leetcode】Word Ladder II
Word Ladder II Given two words (start and end), and a dictionary, find all shortest transformation ...
随机推荐
- Minimum Window Substring
Given a string S and a string T, find the minimum window in S which will contain all the characters ...
- js计算两个日期相隔几小时几分钟?
var dt1 = "2009-11-5 10:30" var dt2 = "2009-11-8 9:20" function ge ...
- WinForm编程数据视图之DataGridView浅析
学习C#语言的朋友们肯定或多或少地接触到了WinForm编程,在C#语言的可视化IDE中(如VS.NET中)使用设计器可以让我们轻松地完成窗体.按钮.标签.图片框等等控件的组合,我们可以轻易地做出界面 ...
- pandas 数据索引与选取
我们对 DataFrame 进行选择,大抵从这三个层次考虑:行列.区域.单元格.其对应使用的方法如下:一. 行,列 --> df[]二. 区域 --> df.loc[], df.ilo ...
- netty定时器HashedWheelTimer(zz)
http://www.tianjiaguo.com/programming-language/java-language/netty%E5%AE%9A%E6%97%B6%E5%99%A8hashedw ...
- 崩溃日志记录工具Crashlytics
http://try.crashlytics.com 申请账号,通常一两天 设置工程 后期更新,个人感觉使用这个很麻烦
- ANSI,UTF8等等这些格式
之前一直在纠结这些格式到底有什么区别,有时候因为格式的问题会让人抓狂. 下面通过实战来分析下: 下面在windows上建立一个txt文档.txt的优势是没有文件头,这样比较好分析. ANSI格式: 可 ...
- EasyUI实战经验总结,给有需要的人
最近公司培训EasyUI,就做下总结吧,给有需要的人. 1.最常用的表格 <div class="easyui-panel" data-options="regio ...
- 360wifi 在 windows server 2008 / 2003 的使用方法
1. 安装驱动 在地址栏输入:Control Panel\System and Security\Administrative Tools , 然后找到Server Manager 打开 Server ...
- 深入学习JavaScript(一)
1.全局变量与局部变量 全局变量:全局变量就是在函数的外部定义的一个在其他地方都可以调用的变量 局部变量:局部变量是相对于全局变量而言的,局部变量指的是在一个区域内存在这个变量 全局变量的创建原理是在 ...