bfs
graph
hash table
]
Leetcode 0126. Word Ladder II
Problem statement
https://leetcode.com/problems/word-ladder-ii/
Solution
The idea of this problem is to run bfs, where one step is changing some letter of word. For me easier to separate problem to two parts:
- Create graph of connections
G. - Run bfs on this graph with collecting all possible solutions.
Now, let us consider steps in more details.
-
To create graph of connections for each word, for example
hit, create patterns*it, h*t, hi*. Then iterate over patterns and connect words in our defaultdictG. -
We need to run bfs, but we also need to give as answer all possible solutions, so, we need to modify our algorithm a bit. We keep two dictionaries:
depsfor depths of each word andpathsto keep all possible paths. When we extract element from queue and look at its neighbours, we need to add new element to queue ifdeps[neib] == -1. Also we need to updatepaths[neib]ifdeps[neib] == -1 or deps[neib] == deps[w] +, that is to deal with all ways of optimal length.
Complexity
We need O(nk^2) time to create all possible patterns: for each of n words we have k patterns with length k. Then we will have no more than O(n*k*26) possible connections for all pairs of words, each of which has length k, so to create G we need O(nk^2*26) time. In practice thought this number is smaller, because graph can not have this number of connections. For the last part with bfs we have complexity O(nk^2*26) again, because this is the number of edges in our graph + A, where A is number of found solutions, which can be exponential. So, time complexity is O(nk^2*26 + A), space is the same.
Code
class Solution:
def findLadders(self, begW, endW, wordList):
wordList += [begW]
n, k = len(wordList), len(wordList[0])
patterns = defaultdict(set)
for word in wordList:
for ind in range(0, k):
tmp = word[0:ind] + "*" + word[ind+1:]
patterns[tmp].add(word)
G = defaultdict(set)
for elem in patterns.values():
for x, y in permutations(elem, 2):
G[x].add(y)
deps = {w: -1 for w in wordList}
deps[begW] = 0
paths = defaultdict(list)
paths[begW] = [[begW]]
queue = deque([begW])
while queue:
w = queue.popleft()
if w == endW: return paths[w]
for neib in G[w]:
if deps[neib] == -1 or deps[neib] == deps[w] + 1:
if deps[neib] == -1:
queue.append(neib)
deps[neib] = deps[w] + 1
for elem in paths[w]:
paths[neib].append(elem + [neib])