[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 ...
随机推荐
- ROWNUMBER() OVER( PARTITION BY COL1 ORDER BY COL2)用法
今天在使用多字段去重时,由于某些字段有多种可能性,只需根据部分字段进行去重,在网上看到了rownumber() over(partition by col1 order by col2)去重的方法,很 ...
- EF code First数据迁移学习笔记(转)
转自:http://www.cnblogs.com/icyJ/p/migration.html 准备工作 1.新建一个控制台项目, 在"程序包管理控制台"执行 Install-pa ...
- python数字图像处理(4):图像数据类型及颜色空间转换
一.图像数据类型及转换 在skimage中,一张图片就是一个简单的numpy数组,数组的数据类型有很多种,相互之间也可以转换.这些数据类型及取值范围如下表所示: Data type Range uin ...
- Google protocol buffer在windows下的编译
在caffe框架中,使用的数据格式是google的 protocol buffer.对这个不了解,所以,想简单学习一下.简单来说,Protocol Buffer 是一种轻便高效的结构化数据存储格式,可 ...
- Android Home键状态保存运用场景
当我们在一个Activity中有接收Intent过来的值,或者当前Activity有保存数据时候,如果此时不小心按到了Home键,然后没有及时回来而是运行了其它应用程序,当你想起来的时候,恐怕已经是几 ...
- Linux常用指令---grep(搜索过滤)
Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达 ...
- 使用JQuery能做什么(zz)
jQuery库为Web脚本编程提供了通用(跨浏览器)的抽象层,使得它几乎适用于任何脚本编程的情形.jQuery通常能为我们提供以下功能: 1.方便快捷获取DOM元素 如果使用纯JavaScript的方 ...
- [CareerCup] 6.2 Dominos on Chess Board 棋盘上的多米诺
6.2 There is an 8x8 chess board in which two diagonally opposite corners have been cut off. You are ...
- [CareerCup] 12.1 Find Mistakes 找程序错误
12.1 Find the mistake(s) in the following code: unsigned int i; ; i >= ; --i) printf("%d\n&q ...
- 20135202闫佳歆--week 8 课本第4章学习笔记
第四章 进程调度 一.多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务操作系统使多个进程处于堵塞或者睡眠状态,实际不被投入执行,这些任务尽管位于内存,但是并不处于可运行状态. ...