Find Words
# Solution
Let be length of str and length of dict. There are two pointers, i in str and j in dict.
Brute force solution is to compare 2 pointers until i gets to end of str. This is not time efficient especially when str is long. So we need to preprocess w/ data structures such as matrix or hashmap.
# Matrix
Go from back to front, nextpos[i][j] is the next position of char j after str[i]. If str[i]==j, then nextpos[i][j] = i.
Complexity
time:
space:
def findWords(self, str, dict):
if not str or not dict:
return []
n, res = len(str), []
nextpos = [[n for _ in range(26)] for _ in range(n+1)]
# preprocessing
for i in reversed(range(n)):
for j in range(26):
nextpos[i][j] = nextpos[i+1][j]
if ord(str[i]) - ord('a') == j:
nextpos[i][j] = i
# `nextpos` can also be dict
# nextpos = {}
# for i in range(n):
# nextpos.setdefault(str[i], []).append(i)
# 2 pointers comparision
for word in dict:
# i points in str, j points in dict
i, j, m = 0, 0, len(word)
while i < n and j < m:
i = nextpos[i][ord(word[j]) - ord('a')]
if i == n: # word not found in str
break
i += 1
j += 1
if j == m:
res.append(word)
return res
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
# Finite Automaton
index records the matched position of words in dict. Search across str, if index[j] is at least as long as length of current word, then word is already matched. Else if char str[i] is equal to next char of word j, increment index[j] by 1.
Note that we can't just append word to res as soon as index[j] >= len(dict[j]), as the problem requires res to be in dictionary order.
Complexity
time:
space:
def findWords(self, str, dict):
n = len(dict)
index = [0 for _ in range(n)]
for i in range(len(str)):
for j in range(n):
# finished matching already
if index[j] >= len(dict[j]):
continue
# if index[j]-th char in j-th word in `dict` matches w/ `str[i]`
# then move index[j] to the right by 1
if dict[j][index[j]] == str[i]:
index[j] += 1
res = []
for j in range(n):
if index[j] >= len(dict[j]):
res.append(dict[j])
return res
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17