1. 定义
我们约定对于字符串 s s s,长度为 s z sz sz
s [ i : ] s[i:] s[i:]为 s i s i + 1 ⋯ s s z − 1 s_is_{i+1}\cdots s_{sz-1} sisi+1⋯ssz−1
z z z函数定义为
s [ 0 : ] 与 s [ i : ] s[0:]与s[i:] s[0:]与s[i:]的最长公共前缀长度。
2. 实现
2.1 暴力
直接从前往后暴力循环
std::vector<int> ExtendKmp::z_function_trivial(std::string s) {
int sz = static_cast<int>(s.size());
std::vector<int> z(sz, 0);
for (int i = 1;i < sz; ++i) {
while ( i + z[i] < sz && s[z[i]] == s[i + z[i]])
z[i]++;
}
return z;
}
2.2 扩展kmp
实际上与 k m p kmp kmp好像没啥关系?感觉跟 m a n a c h e r manacher manacher有点像。
核心的思想就是,当 i + z [ i ] > j i+z[i]>j i+z[i]>j时, z [ j ] = z [ j − i ] z[j] =z[j-i] z[j]=z[j−i]
假设前缀区间为 [ l , r ] [l,r] [l,r]
当
r
>
i
r>i
r>i时,
s
[
i
,
r
]
=
s
[
i
−
l
,
r
−
l
]
,
z
[
i
]
=
z
[
i
−
l
]
s[i,r]=s[i-l,r-l],z[i]=z[i-l]
s[i,r]=s[i−l,r−l],z[i]=z[i−l]
当
r
<
=
i
r <=i
r<=i时,$$
std::vector<int> ExtendKmp::z_function(std::string s) {
int sz = static_cast<int>(s.size());
std::vector<int> z(sz, 0);
int l = 0, r = 0;
for (int i = 1; i < sz; ++i) {
if ( i <= r && i + z[i - l] + 1 < r) {
z[i] = z[i - l];
} else{
z[i] = std::max(0, r - i + 1);
while (i + z[i] < sz && s[z[i]] == s[i + z[i]])
++z[i];
}
if ( i + z[i] > r) {
l = i;
r = i + z[i] ;
}
}
return z;
}