字符串算法果然玄学=_=
参考资料:
OI Wiki:前缀函数与KMP算法
OI Wiki:Z函数(扩展KMP)
0. 约定
字符串的下标从 (0) 开始。
对于长度为 (n) 的字符串 (s),记其每一个字符分别为 (s_0, s_1, cdots, s_{n-1})。
子串 (s_l, s_{l+1}, cdots, s_{r-1}, s_r) 简记为 (s(l,r))。
对于字符串 (a, b),(a+b) 表示拼接操作,即将字符串 (b) 拼接到字符串 (a) 之后,构成新的字符串。
记构成的新字符串为 (c),则上述拼接操作记为 (cgets a+b)。
不论是字符还是字符串,皆不加引号。
1. 前缀函数
1. 前缀函数的定义
对于字符串 (s),若存在一个非本身的子串 (t) 使得 (t) 既是 (s) 的前缀又是 (s) 的后缀,称 (t) 为 (s) 的一个 ( ext{Border})。
更加符号化地,对于一个长为 (n) 的字符串 (s),若存在 (m) 使得 (s
eq m) 且 (s(0,m-1)=s(n-m+1,n)),
称 (s(0,m-1)) ((s(n-m+1,n)) 同理) 为 (s) 的一个长度为 (m) 的 ( ext{Border})。
对于一个字符串 (s),定义 ( ext{MaxBorder}(s)) 为 (s) 的 ( ext{Border}) 中最长的。
接下来定义前缀函数:
对于一个字符串 (s),定义前缀函数 (pi(s,i)) 为 ( ext{MaxBorder}(s(0,i))) 的长度。
在不引起歧义的情况下,可简记为 (pi(i));特别地,定义 (pi(s,0)=0)。
有时我们关心一整个字符串的长度,故此时我们也可以记 (pi(s)={pi(s,0), pi(s,1), cdots, pi(s,n-1)})。
举一个实例:(pi( exttt{abacaba})={0,0,1,0,1,2,3})。
2. 前缀函数的重要性质
显然直接根据定义计算前缀函数的时间复杂度是不能接受的,于是我们需要依赖一些有用的性质来加速计算。
主要的性质有下面两个:
- (pi(i+1)leqslantpi(i)+1),且仅当 (s_{pi(i)}=s_{i+1}) 时有 (pi(i+1)=pi(i)+1)。
- 令 (j) 为 (s(0,i)) 中除 ( ext{MaxBorder}(s(0,i))) 外最长的 ( ext{Border}) 的长度,则 (j=pi(pi(i)-1))。
第一个性质是显然的。第二个性质由 (s(0,j-1)=s(i-j+1,i)=s(pi(i)-j,pi(i)-1)) 自然导出。
3. 快速求前缀函数
这样我们就有了快速求前缀函数的算法:
我们从前向后迭代求。假设我们已经求出了 (pi(0), pi(1), cdots, pi(i-1)),现在要求 (pi(i))。
令 (j=pi(i-1))。如果 (s_i=s_j),则 (pi(i)=j+1)。
否则,令 (jgets pi(j-1)),重复以上判断直到满足 (s_i=s_j) 或 (j=0)。
若 (j=0),则 (pi(i)=0)。
如此重复直到前缀函数全部计算完成。可以证明,时间复杂度为 (O(n))。
code:
void prefix()
{
for(int i=1;i<=n-1;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;
}
}
2. KMP
一般的方法是通过 (pi(i)) 优化匹配,不过有个简单粗暴地多的方法。
假设模式串为 (s),文本串为 (t),(s) 的长度为 (n),(t) 的长度为 (m)。
构造字符串 (agets s+#+t),其中 (#) 是 (s,t) 中均不会出现的字符。
然后求 (a) 的前缀函数,若(pi(a,i)=n),则 (s) 在 (t) 的 (i-2n) 处出现。
总时间复杂度 (O(n+m))。代码略。
优化:注意到前缀函数是可以一个一个字符在线处理的,所以空间复杂度可优化到 (O(n))。
3. Z函数
定义 ( ext{lcp}(a,b)) 为字符串 (a, b) 的最长公共前缀。
定义Z函数:
对于一个长度为 (n) 的字符串 (s),定义Z函数 (z(s,i)) 为 ( ext{lcp}(s,s(i,n-1))) 的长度。
在不引起歧义的情况下,可简记为 (z(i));特别地,定义 (z(s,0)=0)。
有时我们关心一整个字符串的长度,故此时我们也可以记 (z(s)={z(s,0), z(s,1), cdots, z(s,n-1)})。
举一个实例:(z( exttt{abacaba})={0,0,1,0,3,0,1})。