Word Ladder II

All shortest transformation sequences from begin to end — BFS to compute layered distances, DFS to enumerate paths.

Hard
Time O(n * L^2 + 2^n) Space O(n * L)
LeetCode
7 min read
backtracking bfs graph

Problem#

Given beginWord, endWord, and a word list, return all shortest transformation sequences where consecutive words differ by one letter and every intermediate word is in the list.

Examples#

  • begin = "hit", end = "cog", words = ["hot","dot","dog","lot","log","cog"][["hit","hot","dot","dog","cog"],["hit","hot","lot","log","cog"]]

Hints#

Hint 1
Two phases: BFS from beginWord to compute level distances; DFS from endWord backwards using only edges that decrease distance.

Approach#

  1. BFS from beginWord building dist[word] for every word in the list. Stop after the level containing endWord.
  2. DFS from endWord backwards (looking at words at distance dist[curr] - 1) collecting paths.

Solution#

Word Ladder II
class Solution {
public:
vector<vector<string>> findLadders(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> dict(wordList.begin(), wordList.end());
if (!dict.count(endWord)) return {};
unordered_map<string,int> dist;
unordered_map<string, vector<string>> parents;
queue<string> q;
q.push(beginWord);
dist[beginWord] = 0;
bool found = false;
while (!q.empty() && !found) {
int sz = q.size();
unordered_set<string> level;
for (int i = 0; i < sz; ++i) {
string w = q.front(); q.pop();
string s = w;
for (int j = 0; j < (int)s.size(); ++j) {
char orig = s[j];
for (char c = 'a'; c <= 'z'; ++c) {
if (c == orig) continue;
s[j] = c;
if (dict.count(s) && (!dist.count(s) || dist[s] == dist[w] + 1)) {
if (!dist.count(s)) {
dist[s] = dist[w] + 1;
level.insert(s);
}
parents[s].push_back(w);
if (s == endWord) found = true;
}
}
s[j] = orig;
}
}
for (auto& w : level) q.push(w);
}
vector<vector<string>> out;
vector<string> path = {endWord};
function<void(const string&)> dfs = [&](const string& w) {
if (w == beginWord) {
out.push_back({path.rbegin(), path.rend()});
return;
}
for (auto& p : parents[w]) {
path.push_back(p);
dfs(p);
path.pop_back();
}
};
if (found) dfs(endWord);
return out;
}
};

Editorial#

BFS finds shortest distance, but enumerating all shortest paths needs a parent multimap recording every “shortest predecessor”. DFS backward from endWord walks this DAG to emit each path exactly once. The “level set” prevents adding within-level edges as parents.

Complexity#

  • Time: O(n * L^2 + paths * L).
  • Space: O(n * L).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.