126. Word Ladder II
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output:
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]Last updated
Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]
Output:
[
["hit","hot","dot","dog","cog"],
["hit","hot","lot","log","cog"]
]Last updated
Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]
Output: []
Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.// Double-End BFS + Backtracking
void getPaths(const string& word,
const string& endWord,
const unordered_map<string, vector<string> >& children,
vector<string>& path,
vector<vector<string> >& res)
{
if (word == endWord) {
res.push_back(path);
return;
}
const auto it = children.find(word);
if (it == children.cend()) return;
for (const string& child : it->second) {
path.push_back(child);
getPaths(child, endWord, children, path, res);
path.pop_back();
}
}
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
vector<vector<string> > res;
unordered_set<string> dict(wordList.begin(), wordList.end());
if (!dict.count(endWord)) return res;
unordered_set<string> q1({beginWord}), q2({endWord});
unordered_map<string, vector<string> > children;
bool found = false, backward = false;
int l = beginWord.length();
while (!q1.empty() && !q2.empty() && !found) {
// Do BFS from the smaller queue
if (q1.size() > q2.size()) {
swap(q1, q2);
backward = !backward;
}
for (const string& w1 : q1) dict.erase(w1);
for (const string& w2 : q2) dict.erase(w2);
unordered_set<string> tmp_q;
for (const string& word : q1) {
string cur = word;
for (int i = 0; i < l; ++i) {
char ch = cur[i];
for (char j = 'a'; j <= 'z'; ++j) {
cur[i] = j;
const string* parent = &word;
const string* child = &cur;
if (backward) swap(parent, child);
if (q2.count(cur)) {
found = true;
children[*parent].push_back(*child);
} else if (dict.count(cur) && !found) {
tmp_q.insert(cur);
children[*parent].push_back(*child);
}
}
cur[i] = ch;
}
}
swap(q1, tmp_q);
}
if (found) {
vector<string> path({beginWord});
getPaths(beginWord, endWord, children, path, res);
}
return res;
}vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) { // time: O(n * str_len); space: O(n * str_len)
unordered_set<string> words(wordList.begin(), wordList.end());
vector<vector<string> > res;
queue<vector<string> > paths({{beginWord}});
unordered_set<string> visited; // the words visited in the current level
int level = 1, minLevel = INT_MAX;
while (!paths.empty()) {
// a level
for (int k = paths.size() - 1; k >= 0; --k) {
vector<string> path = paths.front(); paths.pop();
string lastWord = path.back();
for (int i = 0; i < lastWord.length(); ++i) {
string newWord = lastWord;
for (char ch = 'a'; ch <= 'z'; ++ch) {
newWord[i] = ch;
if (words.count(newWord)) {
vector<string> newPath = path;
newPath.push_back(newWord);
visited.insert(newWord);
if (newWord == endWord) {
minLevel = level;
res.push_back(newPath);
} else {
paths.push(newPath);
}
}
}
}
}
if (++level > minLevel) break; // pruning, already found minLevel path combination
else {
for (auto& str : visited) words.erase(str);
visited.clear();
}
}
return res;
}