33
44
55
6-
76class Solution :
87 def ladderLength (self , beginWord : str , endWord : str , wordList : List [str ]) -> int :
9- """BFS over a generic-pattern graph.
10-
11- Build buckets keyed by patterns like 'h*t' so every word that differs
12- by a single letter shares a bucket. BFS from beginWord finds the
13- shortest transformation, counting words in the sequence.
148 """
15-
9+ Find the shortest transformation sequence from beginWord to endWord.
10+ Uses BFS to find the shortest path.
11+
12+ Time Complexity: O(M^2 * N) where M is word length, N is wordList size
13+ Space Complexity: O(M^2 * N) for the pattern dictionary
14+ """
15+ # If beginWord equals endWord, the sequence is just the word itself
16+ if beginWord == endWord :
17+ return 1
18+
19+ # If endWord is not in wordList, no valid transformation exists
1620 if endWord not in wordList :
1721 return 0
18-
19- # Map each wildcard pattern -> list of words matching it.
20- patterns = defaultdict (list )
21- for word in wordList :
22- for i in range (len (word )):
23- pattern = word [:i ] + "*" + word [i + 1 :]
24- patterns [pattern ].append (word )
25-
26- # BFS. Level = number of words in the sequence so far (beginWord counts as 1).
27- queue = deque ([(beginWord , 1 )])
22+
23+ # Convert wordList to set for O(1) lookup
24+ word_set = set (wordList )
25+
26+ # Build a pattern dictionary to find all words that differ by one letter
27+ # e.g., "hot" -> {"*ot": ["hot"], "h*t": ["hot"], "ho*": ["hot"]}
28+ pattern_dict = defaultdict (list )
29+ word_len = len (beginWord )
30+
31+ # Add beginWord to the set if not present
32+ if beginWord not in word_set :
33+ word_set .add (beginWord )
34+
35+ # Create patterns for all words
36+ for word in word_set :
37+ for i in range (word_len ):
38+ pattern = word [:i ] + '*' + word [i + 1 :]
39+ pattern_dict [pattern ].append (word )
40+
41+ # BFS to find shortest path
42+ queue = deque ([(beginWord , 1 )]) # (current_word, level)
2843 visited = {beginWord }
29-
44+
3045 while queue :
31- word , level = queue .popleft ()
32-
33- if word == endWord :
34- return level
35-
36- for i in range (len (word )):
37- pattern = word [:i ] + "*" + word [i + 1 :]
38- for neighbor in patterns [pattern ]:
39- if neighbor not in visited :
40- visited .add (neighbor )
41- queue .append ((neighbor , level + 1 ))
42- print (pattern ,visited )
43- # Clear the bucket so it is not scanned again by another word.
44- patterns [pattern ] = []
45-
46+ current_word , level = queue .popleft ()
47+
48+ # Try all possible transformations by replacing each character
49+ for i in range (word_len ):
50+ pattern = current_word [:i ] + '*' + current_word [i + 1 :]
51+
52+ # Get all words matching this pattern
53+ for next_word in pattern_dict [pattern ]:
54+ if next_word == endWord :
55+ return level + 1
56+
57+ if next_word not in visited :
58+ visited .add (next_word )
59+ queue .append ((next_word , level + 1 ))
60+
61+ # Clear the pattern to avoid revisiting in future iterations
62+ pattern_dict [pattern ] = []
63+
4664 return 0
47-
48- print ('hello world' )
49- solution = Solution ()
50-
51- print (solution .ladderLength (beginWord = 'hat' ,endWord = 'hut' , wordList = ['het' ,
52- 'hit' ,
53- 'hot' ,
54- 'hut' ]))
0 commit comments