您的位置:首页 > 其它

LintCode-单词接龙II

2017-07-01 20:27 281 查看
LintCode-单词接龙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"]

]


先直接写了个图+BFS

遍历每两个单词算different,等于1的放进邻接矩阵里面。

然后用没做优化的BFS找end

class Solution {
public:
/**
* @param start, a string
* @param end, a string
* @param dict, a set of string
* @return a list of lists of string
*/
struct Destination {
int num = 0;
vector<string> str;
};
struct Path {
string str;
vector<string> path;
};
map<string,bool> isPassed;
void BFS(queue<Path> &order, vector<vector<string>> &result, map<string, Destination> m, const string end) {
int num = order.size();
for (int i = 0; i < num;i++) {
Path s = order.front();
isPassed[s.str]=true;
order.pop();
if (s.str == end) {
result.push_back(s.path);
}
if (m[s.str].num != 0) {
for (auto i : m[s.str].str) {
if(!isPassed[i])
{
Path p;
p.str = i;
p.path = s.path;
p.path.push_back(i);
order.push(p);
}
}
}
}
if (!order.empty() && result.empty())
BFS(order, result, m, end);
return;
}
vector<vector<
4000
/span><string>> findLadders(string start, string end, unordered_set<string> &dict) {
// write your code here
dict.insert(start);
dict.insert(end);
map<string, Destination> m;
for (auto i : dict) {
Destination d;
for (auto j : dict) {
int diff = 0;
for (int p = 0; p<i.length(); p++) {
if (i[p] != j[p]) diff++;
}
if (diff == 1) {
d.num++;
d.str.push_back(j);
}
}
m[i] = d;
}
queue<Path> order;
Path s;
s.path.push_back(start);
s.str = start;
order.push(s);
vector<vector<string>> result;
BFS(order, result, m, end);
return result;
}
};


过了大概七个case后超时,发现光建map就要用O(n2)。查了一下看到unordered_set的find()函数,于是改成

for (auto i : dict) {
for (int j = 0; j<i.size(); j++) {
for (int k = 0; k<26; k++) {
string tmp = i;
tmp[j] = 'a' + k;
if (dict.find(tmp)!=dict.end() && strcmp(tmp.c_str(), i.c_str())) {
m[i].num++;
m[i].str.push_back(tmp);
}
}
}
}


又多过了一个case,接着是BFS超时

想一想感觉是搜索的时候队列里面会出现大量重复的单词,拖慢速度。

于是做了一个set记录每个单词的“last string”,只有没加入过的next string才能加到队列里面,保证队列里面不会有重复单词。

但这样一来就没办法直接记录path了,于是再利用刚才的set通过BFS反向找一下path,一开始作死想用栈写BFS,结果写了几十行各种出问题放弃了,直接10行递归搞定。

class Solution {
public:
/**
* @param start, a string
* @param end, a string
* @param dict, a set of string
* @return a list of lists of string
*/
struct Destination {
int num = 0;
vector<string> str;
};
struct Node {
unordered_set<string> last;
};
map<string, Node> node;
map<string, bool> isPassed;
vector<vector<string>> result;
void DFS(vector<string> path,string str,int count,const string& start,const int& max) {
path.push_back(str);
if (str == start) {
result.push_back(path);
reverse(result.back().begin(), result.back().end());
}
if (count == max) return;
for (auto i : node[str].last) {
DFS(path, i, count + 1, start, max);
}
return;
}
void BFS(queue<string> &order, map<string, Destination> m, const string start,const string end) {
int max=1;
while (!order.empty() && !node[end].last.size()) {
int num = order.size();
max++;
for (int i = 0; i < num; i++) {
string s = order.front();
isPassed[s] = true;
order.pop();
if (m[s].num != 0) {
for (auto i : m[s].str) {
if (!isPassed[i]) {
if (node[i].last.size() == 0) {
order.push(i);
}
node[i].last.insert(s);
}
}
}
}
}
vector<string> path;
DFS(path, end, 1, start, max);
return;
}

vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
// write your code here
dict.insert(start);
dict.insert(end);
map<string, Destination> m;
for (auto i : dict) { for (int j = 0; j<i.size(); j++) { for (int k = 0; k<26; k++) { string tmp = i; tmp[j] = 'a' + k; if (dict.find(tmp)!=dict.end() && strcmp(tmp.c_str(), i.c_str())) { m[i].num++; m[i].str.push_back(tmp); } } } }
queue<string> order;
order.push(start);
BFS(order, m, start,end);

return result;
}
};


总共跑了500多ms,网上的代码大概300ms,贴下来有空再看

class Solution {
public:
/**
* @param start, a string
* @param end, a string
* @param dict, a set of string
* @return a list of lists of string
*/
vector<vector<string>> findLadders(string start, string end, unordered_set<string> &dict) {
// write your code here
vector<vector<string> > result;
set<string> cur;
cur.insert(start);
set<string> next;
map<string, set<string> > parents;

unordered_set<string> unused = dict;
unused.insert(end);

visit(cur, end, next, unused, parents);
if (parents.find(end) != parents.end())
{
vector<string> buf;
generatePath(start, end, parents, buf, result);
}

return result;
}
private:
void visit(set<string> &cur, string &end, set<string> &next,
unordered_set<string> &unused, map<string, set<string> > &parents)
{
while (parents.find(end) == parents.end() && !unused.empty())
{
next.clear();
for (set<string>::iterator it = cur.begin(); it != cur.end(); it++)
{
string word = *it;
string temp = *it;
for (int i = 0; i < (*it).length(); i++)
{
for (char a = 'a'; a <= 'z'; a++)
{
temp = *it;
if (a != word[i])
{
temp[i] = a;
if (unused.find(temp) != unused.end())
{
parents[temp].insert(word);
next.insert(temp);
}
}
}
}
}

if (next.empty())
{
return;
}

cur = next;
<
b35e
span class="hljs-keyword">for (set<string>::iterator it = next.begin(); it != next.end(); it++)
{
unused.erase(*it);
}
}
}

void generatePath(string &start, string cur, map<string, set<string> > &parents,
vector<string> &buf, vector<vector<string> > &result)
{
buf.insert(buf.begin(), cur);
if (cur == start)
{
result.push_back(buf);
}
else
{
for (set<string>::iterator it = parents[cur].begin(); it != parents[cur].end(); it++)
{
generatePath(start, *it, parents, buf, result);
}
}

buf.erase(buf.begin());
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  lintcode bfs