forked from algorhythms/Algo-Quicksheet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapterString.tex
120 lines (111 loc) · 3.15 KB
/
chapterString.tex
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
\chapter{String}
\section{Palindrome}
\subsection{Palindrome anagram}
\runinhead{Test palindrome anagram.} Char counter, number of odd count should $\leq 0$.
\runinhead{Count palindrome anagram.} See Section-\ref{N_objects_K_types}.
\runinhead{Construct palindrome anagram.} Construct all palindrome anagrams given a string \pyinline{s}.
\\
Clues:
\begin{enumerate}
\item dfs, grow the counter map of \pyinline{s}.
\item jump parent char
\end{enumerate}
Code:
\begin{python}
def grow(self, s, count_map, pi, cur, ret):
if len(cur) == len(s):
ret.append(cur)
return
for k in count_map.keys():
if k != pi and count_map[k] > 0:
# jump the parent
for i in xrange(1, count_map[k]/2+1):
count_map[k] -= i*2
self.grow(s, count_map, k, k*i+cur+k*i, ret)
count_map[k] += i*2
\end{python}
\section{KMP}
Find string $W$ in string $S$ within complexity of $O(|W|+|S|)$.
\subsection{Prefix suffix table}
Partial match table (also known as "failure function"). After a failure matching, you know that the matched suffix before the failure point is already matched; therefore when you shift the $W$, you only need to shift the prefix onto the position of the previous suffix. The prefix and suffix must be proper prefix and suffix.
\begin{figure}[hbtp]
\centering
\subfloat{\includegraphics[scale=1.30]{kmp_table}}
\caption{Prefix-suffix table}
\label{fig:kmp_table}
\end{figure}
In table-building algorithm, similar to dp, let $T[i]$ store the length of matched prefix suffix for $needle[:i]$\\
\\
Clues:
\begin{enumerate}
\item dummy at $T[0]=-1$.
\item three parts
\begin{enumerate}
\item matched
\item fall back (consider $ABABC...ABABA$)
\item restart
\end{enumerate}
\end{enumerate}
Table-building code:
\begin{python}
# construct T
T = [0 for _ in xrange(len(needle)+1)]
T[0] = -1
T[1] = 0
cnd = 0
i = 2 # table index
while i < len(needle)+1:
if needle[i-1] == needle[cnd]: # matched
T[i] = cnd+1
cnd += 1
i += 1
elif T[cnd] != -1: # fall back
cnd = T[cnd]
else: # restart
T[i] = 0
cnd = 0
i += 1
\end{python}
\subsection{Searching algorithm}
\begin{figure}[F]
\centering
\subfloat{\includegraphics[scale=1.30]{kmp_presuffix}}
\caption{KMP example}
\label{fig:kmp_presuffix}
\end{figure}
Notice:
\begin{enumerate}
\item index $i$ and $j$.
\item $T[i-1+1]$ for corresponding previous index in $T$ for current scanning index $i$.
\item When falling back, the next scanning index is \pyinline{len(prefix)}
\item three parts:
\begin{enumerate}
\item matched
\item aggressive move and fall back
\item restart
\end{enumerate}
\end{enumerate}
Search code:
\begin{python}
# search
i = 0 # index for needle
j = 0 # index for haystack
while j+i < len(haystack):
if needle[i] == haystack[j+i]: # matched
i += 1
if i == len(needle):
return haystack[j:]
else:
if T[i] != -1: # move and fall back j
j = j+i-T[i]
i = T[i]
else: # restart
j += 1
i = 0
return None
\end{python}
\subsection{Applications}
\begin{enumerate}
\item Find needle in haystack.
\item Shortest palindrome
\end{enumerate}