from collections import defaultdict, deque
class Solution:
def ladderLength(self, beginWord, endWord, wordList):
if endWord not in wordList:
return 0
if beginWord not in wordList:
wordList.append(beginWord)
# record graph[pattern] = corresponding words
# E.g., '*ot': ['hot', 'dot', 'lot']
graph = defaultdict(list)
for word in wordList:
for i in range(len(word)):
pattern = word[:i] + '*' + word[i+1:]
graph[pattern].append(word)
# BFS - q: deque to pop current word; path: record words already seen
q = deque([beginWord])
path = set()
path.add(beginWord)
count = 1
while q:
for i in range(len(q)):
word = q.popleft()
if word == endWord:
return count
for j in range(len(word)):
pattern = word[:j] + '*' + word[j+1:]
# for each word following this pattern
for w in graph[pattern]:
if w not in path:
q.append(w)
path.add(w)
# path length += 1
count += 1
return 0