Word Ladder
The `[node, distance]` queue from `shortestPath` carried over unchanged, but there's no edge list to build a graph from first — the graph is implicit, so a neighbour is discovered by trying every letter at every position and checking a `Set` of the remaining words instead of looking up a precomputed adjacency list.
The problem
Given `beginWord`, `endWord`, and `wordList`, return the number of words in the shortest transformation sequence from `beginWord` to `endWord`, changing exactly one letter per step and landing on a word in `wordList` at every step, or `0` if no such sequence exists.
`beginWord = "cat", endWord = "sag", wordList = ["bat","bag","sag","dag","dot"]` returns `4`: `cat -> bat -> bag -> sag`. If `"sag"` weren't in `wordList` at all, the answer would be `0` regardless of what else the list contained — `endWord` itself has to be reachable, i.e. present in the list.
The approach
There's no `edges` array to turn into a graph here — the adjacency is implicit in the alphabet. So instead of indexing into a precomputed adjacency list like every earlier BFS in this log, a neighbour of `word` is generated on the fly: for each of its positions, swap in each of the 26 letters and check whether the result is a real word still left in a `Set` built from `wordList`.
That `Set` doubles as both the dictionary and the `visited` structure `shortestPath`/`hasPath` used a separate `Set` for — a candidate gets `delete`d the moment it's queued, so it can never be regenerated as a neighbour of some other word later, and there's no second lookup needed to tell 'is this a real word' from 'have I already used this word'.
The queue is exactly `shortestPath`'s `[node, distanceFromSource]` tuple, renamed to `[word, length]` and seeded at `1` instead of `0` — this problem counts *words* in the sequence, not *edges* between them, so `beginWord` itself is the first word already, and the early-return shape (check the candidate against `endWord` before deleting/pushing, return immediately) carries over untouched.
The solution
class Solution {
/**
* @param {string} beginWord
* @param {string} endWord
* @param {string[]} wordList
* @return {number}
*/
ladderLength(beginWord, endWord, wordList) {
const wordSet = new Set(wordList);
if (!wordSet.has(endWord)) return 0;
wordSet.delete(beginWord);
const q = [[beginWord, 1]];
while (q.length) {
const [word, length] = q.shift();
for (let i = 0; i < word.length; i++) {
for (let code = 97; code <= 122; code++) {
const candidate = word.slice(0, i) + String.fromCharCode(code) + word.slice(i + 1);
if (wordSet.has(candidate)) {
if (candidate === endWord) return length + 1;
wordSet.delete(candidate);
q.push([candidate, length + 1]);
}
}
}
}
return 0;
}
}Time O(n * L^2)Space O(n * L)