-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path212. Word Search II.py
77 lines (57 loc) · 2.32 KB
/
212. Word Search II.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
"""
Backtracking solution using a trie
1. Create a trie containing every word
2. Do a DFS on every cell:
i. mark the current node as visited
ii. for every adjacent nodes, if it is a children of the current node in the trie, use dfs
3. Restore the state of the board by removing the current node from visited
Further optimizations possible:
- Keep track of the parent node instead of the current node in the dfs function.
This way, we can make the trie smaller (and reduce search time) by removing nodes
after we find a word.
"""
from typing import List
from collections import defaultdict
class TrieNode:
def __init__(self):
self.children = defaultdict(TrieNode)
self.word = None
def insert(self, word):
cur = self
for letter in word:
cur = cur.children[letter] # defaultdict will create empty node if needed
cur.word = word # end node contains the word
def findWords(board: List[List[str]], words: List[str]) -> List[str]:
n, m = len(board), len(board[0])
dir_4 = [(1, 0), (0, 1), (-1, 0), (0, -1)]
trie = TrieNode()
res = [] # list of found words
for word in words:
trie.insert(word)
def dfs(row, col, cur):
# cur represents the TrieNode for the current cell
if cur.word:
res.append(cur.word) # found a word
cur.word = None # mark as found to prevent duplicates
# mark as visited, store value for later
temp = board[row][col]
board[row][col] = "#"
# try adjacent cells
for dr, dc in dir_4:
new_r = row + dr
new_c = col + dc
# stay inside the board to prevent index out of range
if 0 <= new_r < n and 0 <= new_c < m:
adj = board[new_r][new_c]
if adj in cur.children:
dfs(new_r, new_c, cur.children[adj])
board[row][col] = temp # backtrack
# start a dfs from all cells where the first letter matches a word
for i in range(n):
for j in range(m):
cell = board[i][j]
if cell[0] in trie.children:
dfs(i, j, trie.children[cell])
return res
print(findWords(board=[["o", "a", "a", "n"], ["e", "t", "a", "e"], ["i", "h", "k", "r"], ["i", "f", "l", "v"]],
words=["oath", "pea", "eat", "rain"]))