-
Notifications
You must be signed in to change notification settings - Fork 17
/
word-ladder.py
97 lines (66 loc) · 2.9 KB
/
word-ladder.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
from typing import List, Set, Deque, Tuple, Dict
from collections import deque
class TrieNode:
def __init__(self) -> None:
self.children: Dict[str, TrieNode] = {}
self.word = -1
def __repr__(self) -> str:
return f"TrieNode: [children: {self.children}, word: {self.word}]"
class Solution:
def ladderLength(self, begin_word: str, end_word: str, words: List[str]) -> int:
def distance(words: List[str], left: int, right: int) -> int:
diff = 0
for pos in range(len(words[left])):
if words[left][pos] != words[right][pos]:
diff += 1
return diff
def gen_adj_list(words: List[str]) -> List[List[int]]:
adj_list: List[List[int]] = [[] for _ in words]
for left in range(len(words)):
for right in range(len(words)):
if distance(words, left, right) == 1:
adj_list[left].append(right)
return adj_list
def build_trie(words: List[str]) -> TrieNode:
trie_root = TrieNode()
for word in range(len(words)):
trie_node = trie_root
for pos in range(len(words[word])):
trie_node.children.setdefault(words[word][pos], TrieNode())
trie_node = trie_node.children[words[word][pos]]
trie_node.word = word
return trie_root
def diff_by_one(trie_root: TrieNode, word: str) -> List[int]:
result = []
def dfs(trie_node: TrieNode, pos: int, skip_pos: int) -> None:
if pos == len(word):
result.append(trie_node.word)
return
if pos == skip_pos:
for child in trie_node.children.keys():
dfs(trie_node.children[child], pos + 1, skip_pos)
elif word[pos] in trie_node.children:
dfs(trie_node.children[word[pos]], pos + 1, skip_pos)
for skip_pos in range(len(word)):
dfs(trie_root, 0, skip_pos)
return result
if end_word not in words:
return 0
if begin_word not in words:
words.append(begin_word)
# adj_list: List[List[int]] = gen_adj_list(words)
trie_root: TrieNode = build_trie(words)
# print(trie_root)
src, dst = words.index(begin_word), words.index(end_word)
queue: Deque[Tuple[int, int]] = deque()
queue.append((src, 1))
visited: Set[int] = {src}
while queue:
word, length = queue.popleft()
if word == dst:
return length
for next_word in diff_by_one(trie_root, words[word]):
if next_word not in visited:
queue.append((next_word, length + 1))
visited.add(next_word)
return 0