6.4Word Ladder Ⅱ -- 广度优先搜索
这个题太难搞了!先说明一下
题目描述
给定一个起始字符串和一个终止字符串,以及一个单词表,求是否可以将其实字符串每次改一个字符,直到改成终止字符串,且所有中间的修改过程表示的字符串都可以在单词表里找到。若存在,输出需要修改次数最少的所有更改方式
输入输出样例
Input: beginWord = "hit", endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output:
\["hit","hot","dot","dog","cog"\], \["hit","hot","lot","log","cog"
]
输入两个字符串,输出一个二维字符串数组,表示每种字符串修改方式。
题解
我们可以把起始字符串,终止字符串,以及单词表里的所有字符串想象成节点。若两个字符串只有一个字符不同,那么它们相连。因为题目需要输出修改次数最少的所有修改方式,因此我们可以使用广度优先搜索,求得起始节点到终止节点的最短距离。
还需要用到一个小技巧:我们把"从起始节点进行广度优先搜索,直到找到终止节点",转变为"从起始节点和终止节点分别进行广度优先搜索,每次只延展当前层节点数最少的那一端",通过这种方法,减少搜索的总结点数。
搜索结束后,还得用回溯法来重建所有可能的路径
cpp
#include <vector>
#include <iostream>
#include <unordered_set>
#include <unordered_map>
using namespace std;
// 辅函数
void backtracking(const string& src, const string& dst, unordered_map<string, vector<string>>& next, vector<string>& path, vector<vector<string>>& ans) {
if (src == dst) {
ans.push_back(path);
return;
}
for (const auto& s : next[src]) {
path.push_back(s);
backtracking(s, dst, next, path, ans);
path.pop_back();
}
}
// 主函数
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
vector<vector<string>> ans;
unordered_set<string> dict;
for (const auto& w : wordList) {
dict.insert(w);
}
if (!dict.count(endWord)) {
return ans;
}
dict.erase(beginWord);
dict.erase(endWord);
unordered_set<string> q1{ beginWord }, q2{ endWord };
unordered_map<string, vector<string>> next;
bool reversed = false, found = false;
while (!q1.empty()) {
unordered_set<string> q;
for (const auto& w : q1) {
string s = w;
for (size_t i = 0; i < s.size(); i++) {
char ch = s[i];
for (int j = 0; j < 26; j++) {
s[i] = j + 'a';
if (q2.count(s)) {
reversed ? next[s].push_back(w) : next[w].push_back(s);
found = true;
}
if (dict.count(s)) {
reversed ? next[s].push_back(w) : next[w].push_back(s);
q.insert(s);
}
}
s[i] = ch;
}
}
if (found) {
break;
}
for (const auto& w : q) {
dict.erase(w);
}
if (q.size() <= q2.size()) {
q1 = q;
}
else {
reversed = !reversed;
q1 = q2;
q2 = q;
}
}
if (found) {
vector<string> path = { beginWord };
backtracking(beginWord, endWord, next, path, ans);
}
return ans;
}
int main() {
string beginWord = "hit", endWord = "cog";
vector<string> wordList = { "hot","dot","dog","lot","log","cog" };
vector<vector<string>> res = findLadders(beginWord, endWord, wordList);
cout << "Output:" << endl;
cout << "[" << endl;
for (int i = 0; i < res.size(); ++i) {
cout << " [";
for (int j = 0; j < res[i].size(); ++j) {
cout << "\"" << res[i][j] << "\"";
if (j != res[i].size() - 1) cout << ",";
}
cout << "]";
if (i != res.size() - 1) cout << ",";
cout << endl;
}
cout << "]" << endl;
return 0;
}