知识点 - KMP
解决问题类型:
前缀函数
查找子串
每个前缀的出现次数
本质不同子串的个数O(n^2)
字符串压缩:找到t使得s可以被多个t重复出现得到
前缀自动机
Z函数
查找子串
本质不同子串的个数O(n^2)
字符串压缩
定义与代码:
前缀函数
π
\pi
π(prefix function):
π
[
i
]
\pi[i]
π[i]代表子串
s
[
0
…
i
]
s[0 \dots i]
s[0…i]与其后缀相等的最长真前缀(proper prefix,即不包含本身的前缀)。
π
[
i
]
=
max
k
=
0
…
i
{
k
:
s
[
0
…
k
−
1
]
=
s
[
i
−
(
k
−
1
)
…
i
]
}
\pi[i] = \max_ {k = 0 \dots i} \{k : s[0 \dots k-1] = s[i-(k-1) \dots i] \}
π[i]=k=0…imax{k:s[0…k−1]=s[i−(k−1)…i]}
“aabaaab” -
[
0
,
1
,
0
,
1
,
2
,
2
,
3
]
[0, 1, 0, 1, 2, 2, 3]
[0,1,0,1,2,2,3].
O ( n ) O(n) O(n),在线
vector<int> prefix_function(string s) {
int n = (int)s.length();
vector<int> pi(n);
for (int i = 1; i < n; i++) {
int j = pi[i-1];
while (j > 0 && s[i] != s[j])
j = pi[j-1];
if (s[i] == s[j])
j++;
pi[i] = j;
}
return pi;
}
Z函数: z [ i ] z[i] z[i]代表串s 和其后缀 s [ i . . . n − 1 ] s[i...n-1] s[i...n−1] 的LCP, 定义z[0]=0
“abacaba” - [ 0 , 0 , 1 , 0 , 3 , 0 , 1 ] [0, 0, 1, 0, 3, 0, 1] [0,0,1,0,3,0,1]
O ( n ) O(n) O(n),
vector<int> z_function(string s) {
int n = (int) s.length();
vector<int> z(n);
for (int i = 1, l = 0, r = 0; i < n; ++i) {
if (i <= r)
z[i] = min (r - i + 1, z[i - l]);
while (i + z[i] < n && s[z[i]] == s[i + z[i]])
++z[i];
if (i + z[i] - 1 > r)
l = i, r = i + z[i] - 1;
}
return z;
}
例题
prefix
- UVA # 455 “Periodic Strings”
- UVA # 11022 “String Factoring”
- UVA # 11452 “Dancing the Cheeky-Cheeky”
- UVA 12604 - Caesar Cipher
- UVA 12467 - Secret Word
- UVA 11019 - Matrix Matcher
- SPOJ - Pattern Find
- Codeforces - Anthem of Berland
- Codeforces - MUH and Cube Walls
Z