使用BFS的字梯2
Word ladder 2 using BFS
海编辑!!以下
我正在编写一个字梯算法。用户输入开始词、结束词和所有词的散列。该算法 returns 从起始词到结束词的所有最短路径(如果存在则为多个)。例如 -> start_word = 'cold' , end_word = 'warm'
output = [[ cold -> cord-> card-> ward-> warm], [/如果存在另一路径/]].
每个连续的单词都与前一个单词相差一个字符。我正在使用 BFS 搜索来解决这个问题。我的策略是 return 所有路径,然后 select returned 列表中最短的路径。这是我 return 所有路径的代码:
auto word_ladder::generate(std::string const& from, std::string const& to, absl::flat_hash_set<std::string> const& lexicon) -> std::vector<std::vector<std::string>> {
absl::flat_hash_set<std::string> visited = {};
std::queue<std::vector<std::string>> search_queue = {};
std::vector<std::vector<std::string>> paths = {};
search_queue.push(std::vector<std::string>{from});
while (!search_queue.empty()) {
auto word = search_queue.front();
search_queue.pop();
auto neighbours = generate_neighbours(word.back(), lexicon);
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
continue;
}
if (visited.find(i) != visited.end()) {
continue;
}
search_queue.push(new_word);
visited.insert(i);
}
}
return paths;
}
它有 return 多条路径,但问题是它没有 return 所有路径。它 returns 的路径之一是 ->
1) 清醒、意识到、sware、share、shire、shirr、shier、sheer、sheep、sleep
但是它没有 return 路径 -> 2) "awake","aware","sware","share","sharn" ,"shawn","shewn","sheen","sheep","sleep"
我很确定原因是因为我编码它的方式,它在第一次遇到它时将 "share" 标记为已访问(在 1 中))。因此它不会通过第二条路径(in 2))
为了解决这个问题,我稍微更改了 for 循环:
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
continue;
}
for (auto &j: word) {
if (j == i) {
continue;
}
}
search_queue.push(new_word);
}
我们的想法是检查是否在您在队列中跟踪的路径中访问了该词,而不是全局访问。但是,由于某种原因,此解决方案在某处陷入循环并且不会终止(我假设是由于大型数据集?)。
是不是我的代码有问题,还是因为数据集大,耗时太长?我怎样才能更好地实现解决方案?
编辑!!!
我现在不是寻找所有路径,而是寻找最短路径的长度,然后执行 BFS 直到该深度以获得该深度的所有路径。
auto word_ladder::generate(std::string const& from, std::string const& to, absl::flat_hash_set<std::string> const& lexicon) -> std::vector<std::vector<std::string>> {
absl::flat_hash_set<std::string> visited = {};
visited.insert(from);
std::queue<std::vector<std::string>> search_queue = {};
std::vector<std::vector<std::string>> paths = {};
search_queue.push(std::vector<std::string>{from});
auto length = find_shortest_path_length(from, to, lexicon);
std::cout << "length is: " << length << "\n";
// auto level = 0;
std::unordered_map<std::string, int> level_track = {};
level_track[from] = 0;
while (!search_queue.empty() ) {
auto word = search_queue.front();
search_queue.pop();
// **
if (level_track[word.back()] <= length) {
auto neighbours = generate_neighbours(word.back(), lexicon);
const auto &parent = word.back();
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
std::cout << "The level at the path was " << level_track[parent] << "\n";
continue;
}
if (path_crossed(word, i)) {
continue;
}
search_queue.push(new_word);
level_track[i] = level_track[parent] + 1;
}
}
}
return paths;
}
解决方案现在终止,所以之前的问题肯定是大量搜索。但是我的算法仍然没有给我正确的答案,因为我跟踪节点(单词)深度的方式在某种程度上是不正确的。
您正试图找到一个有效的解决方案,但很可能它不存在。参见 this answer。枚举 所有 条最短路径的成本可能非常高。
海编辑!!以下
我正在编写一个字梯算法。用户输入开始词、结束词和所有词的散列。该算法 returns 从起始词到结束词的所有最短路径(如果存在则为多个)。例如 -> start_word = 'cold' , end_word = 'warm'
output = [[ cold -> cord-> card-> ward-> warm], [/如果存在另一路径/]].
每个连续的单词都与前一个单词相差一个字符。我正在使用 BFS 搜索来解决这个问题。我的策略是 return 所有路径,然后 select returned 列表中最短的路径。这是我 return 所有路径的代码:
auto word_ladder::generate(std::string const& from, std::string const& to, absl::flat_hash_set<std::string> const& lexicon) -> std::vector<std::vector<std::string>> {
absl::flat_hash_set<std::string> visited = {};
std::queue<std::vector<std::string>> search_queue = {};
std::vector<std::vector<std::string>> paths = {};
search_queue.push(std::vector<std::string>{from});
while (!search_queue.empty()) {
auto word = search_queue.front();
search_queue.pop();
auto neighbours = generate_neighbours(word.back(), lexicon);
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
continue;
}
if (visited.find(i) != visited.end()) {
continue;
}
search_queue.push(new_word);
visited.insert(i);
}
}
return paths;
}
它有 return 多条路径,但问题是它没有 return 所有路径。它 returns 的路径之一是 ->
1) 清醒、意识到、sware、share、shire、shirr、shier、sheer、sheep、sleep
但是它没有 return 路径 -> 2) "awake","aware","sware","share","sharn" ,"shawn","shewn","sheen","sheep","sleep"
我很确定原因是因为我编码它的方式,它在第一次遇到它时将 "share" 标记为已访问(在 1 中))。因此它不会通过第二条路径(in 2))
为了解决这个问题,我稍微更改了 for 循环:
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
continue;
}
for (auto &j: word) {
if (j == i) {
continue;
}
}
search_queue.push(new_word);
}
我们的想法是检查是否在您在队列中跟踪的路径中访问了该词,而不是全局访问。但是,由于某种原因,此解决方案在某处陷入循环并且不会终止(我假设是由于大型数据集?)。
是不是我的代码有问题,还是因为数据集大,耗时太长?我怎样才能更好地实现解决方案?
编辑!!!
我现在不是寻找所有路径,而是寻找最短路径的长度,然后执行 BFS 直到该深度以获得该深度的所有路径。
auto word_ladder::generate(std::string const& from, std::string const& to, absl::flat_hash_set<std::string> const& lexicon) -> std::vector<std::vector<std::string>> {
absl::flat_hash_set<std::string> visited = {};
visited.insert(from);
std::queue<std::vector<std::string>> search_queue = {};
std::vector<std::vector<std::string>> paths = {};
search_queue.push(std::vector<std::string>{from});
auto length = find_shortest_path_length(from, to, lexicon);
std::cout << "length is: " << length << "\n";
// auto level = 0;
std::unordered_map<std::string, int> level_track = {};
level_track[from] = 0;
while (!search_queue.empty() ) {
auto word = search_queue.front();
search_queue.pop();
// **
if (level_track[word.back()] <= length) {
auto neighbours = generate_neighbours(word.back(), lexicon);
const auto &parent = word.back();
for (auto &i: neighbours) {
auto new_word = word;
new_word.push_back(i);
if (i == to) {
paths.push_back(new_word);
std::cout << "The level at the path was " << level_track[parent] << "\n";
continue;
}
if (path_crossed(word, i)) {
continue;
}
search_queue.push(new_word);
level_track[i] = level_track[parent] + 1;
}
}
}
return paths;
}
解决方案现在终止,所以之前的问题肯定是大量搜索。但是我的算法仍然没有给我正确的答案,因为我跟踪节点(单词)深度的方式在某种程度上是不正确的。
您正试图找到一个有效的解决方案,但很可能它不存在。参见 this answer。枚举 所有 条最短路径的成本可能非常高。