Shortest Word Transformation Chain

hard graph bfs string

Problem

Given a beginWord, an endWord, and a list of valid intermediate words, return the number of words in the shortest chain that transforms begin into end one letter at a time. Every intermediate word must be in the dictionary. Return 0 if no chain exists.

Words are nodes; two words are adjacent iff they differ in exactly one letter. BFS layered by mutation depth gives the shortest path; the answer is depth + 1 (counting both endpoints).

Inputbegin = "hit", end = "cog", words = [hot, dot, dog, lot, log, cog]
Output5
hit → hot → dot → dog → cog (or via lot/log) is 5 words.

from collections import deque
def ladder_length(begin, end, words):
    bank = set(words)
    if end not in bank: return 0
    seen = {begin}; q = deque([(begin, 1)])
    while q:
        s, d = q.popleft()
        if s == end: return d
        for i in range(len(s)):
            for c in "abcdefghijklmnopqrstuvwxyz":
                if c == s[i]: continue
                t = s[:i] + c + s[i+1:]
                if t in bank and t not in seen:
                    seen.add(t); q.append((t, d + 1))
    return 0
function ladderLength(begin, end, words) {
  const bank = new Set(words);
  if (!bank.has(end)) return 0;
  const seen = new Set([begin]);
  const q = [[begin, 1]];
  while (q.length) {
    const [s, d] = q.shift();
    if (s === end) return d;
    for (let i = 0; i < s.length; i++) {
      for (let c = 97; c < 123; c++) {
        const ch = String.fromCharCode(c);
        if (ch === s[i]) continue;
        const t = s.slice(0, i) + ch + s.slice(i + 1);
        if (bank.has(t) && !seen.has(t)) { seen.add(t); q.push([t, d + 1]); }
      }
    }
  }
  return 0;
}
int ladderLength(String begin, String end, List<String> words) {
    Set<String> bank = new HashSet<>(words);
    if (!bank.contains(end)) return 0;
    Set<String> seen = new HashSet<>(); seen.add(begin);
    Deque<Object[]> q = new ArrayDeque<>();
    q.add(new Object[]{begin, 1});
    while (!q.isEmpty()) {
        Object[] cur = q.poll();
        String s = (String) cur[0]; int d = (int) cur[1];
        if (s.equals(end)) return d;
        char[] arr = s.toCharArray();
        for (int i = 0; i < arr.length; i++) {
            char orig = arr[i];
            for (char c = 'a'; c <= 'z'; c++) {
                if (c == orig) continue;
                arr[i] = c;
                String t = new String(arr);
                if (bank.contains(t) && seen.add(t)) q.add(new Object[]{t, d + 1});
            }
            arr[i] = orig;
        }
    }
    return 0;
}
int ladderLength(string begin, string end, vector<string>& words) {
    unordered_set<string> bank(words.begin(), words.end());
    if (!bank.count(end)) return 0;
    unordered_set<string> seen{begin};
    queue<pair<string,int>> q; q.push({begin, 1});
    while (!q.empty()) {
        auto [s, d] = q.front(); q.pop();
        if (s == end) return d;
        for (int i = 0; i < (int)s.size(); i++) {
            char orig = s[i];
            for (char c = 'a'; c <= 'z'; c++) {
                if (c == orig) continue;
                s[i] = c;
                if (bank.count(s) && !seen.count(s)) { seen.insert(s); q.push({s, d + 1}); }
            }
            s[i] = orig;
        }
    }
    return 0;
}
Time: O(N · L · 26) Space: O(N · L)