Skip to content

Commit 3888c79

Browse files
committed
Time: 135 ms (92.32%), Space: 17.5 MB (46.25%) - LeetHub
1 parent 9cea548 commit 3888c79

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

127-word-ladder/127-word-ladder.py

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
from collections import defaultdict
2+
class Solution(object):
3+
def __init__(self):
4+
self.length = 0
5+
# Dictionary to hold combination of words that can be formed,
6+
# from any given word. By changing one letter at a time.
7+
self.all_combo_dict = defaultdict(list)
8+
9+
def visitWordNode(self, queue, visited, others_visited):
10+
queue_size = len(queue)
11+
for _ in range(queue_size):
12+
current_word = queue.popleft()
13+
for i in range(self.length):
14+
# Intermediate words for current word
15+
intermediate_word = current_word[:i] + "*" + current_word[i+1:]
16+
17+
# Next states are all the words which share the same intermediate state.
18+
for word in self.all_combo_dict[intermediate_word]:
19+
# If the intermediate state/word has already been visited from the
20+
# other parallel traversal this means we have found the answer.
21+
if word in others_visited:
22+
return visited[current_word] + others_visited[word]
23+
if word not in visited:
24+
# Save the level as the value of the dictionary, to save number of hops.
25+
visited[word] = visited[current_word] + 1
26+
queue.append(word)
27+
28+
return None
29+
30+
def ladderLength(self, beginWord, endWord, wordList):
31+
"""
32+
:type beginWord: str
33+
:type endWord: str
34+
:type wordList: List[str]
35+
:rtype: int
36+
"""
37+
if endWord not in wordList or not endWord or not beginWord or not wordList:
38+
return 0
39+
40+
# Since all words are of same length.
41+
self.length = len(beginWord)
42+
43+
for word in wordList:
44+
for i in range(self.length):
45+
# Key is the generic word
46+
# Value is a list of words which have the same intermediate generic word.
47+
self.all_combo_dict[word[:i] + "*" + word[i+1:]].append(word)
48+
49+
# Queues for birdirectional BFS
50+
queue_begin = collections.deque([beginWord]) # BFS starting from beginWord
51+
queue_end = collections.deque([endWord]) # BFS starting from endWord
52+
53+
# Visited to make sure we don't repeat processing same word
54+
visited_begin = {beginWord : 1}
55+
visited_end = {endWord : 1}
56+
ans = None
57+
58+
# We do a birdirectional search starting one pointer from begin
59+
# word and one pointer from end word. Hopping one by one.
60+
while queue_begin and queue_end:
61+
62+
# Progress forward one step from the shorter queue
63+
if len(queue_begin) <= len(queue_end):
64+
ans = self.visitWordNode(queue_begin, visited_begin, visited_end)
65+
else:
66+
ans = self.visitWordNode(queue_end, visited_end, visited_begin)
67+
if ans:
68+
return ans
69+
70+
return 0

0 commit comments

Comments
 (0)