之前刷了KMP专题,后来发现全忘了。比赛的时候连kmp怎么写都忘了。(算法学了就忘,真想打死自己)所以就来写写博客,整理一下,顺便回想一下。
大概会分三四篇来写,写下基本的kmp,然后kmp的应用, Manacher,还有最大最小表示法。至于扩展kmp,感觉kmp还是可以解决的(一点拙见), 就没学。
基本kmp
Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
char str1[maxn], str2[maxn];
int Next[maxn];
void get_Next()
{
int i, j, m = strlen(str2);
Next[0] = 0;
for(i = 1; i < m; i++)
{
j = Next[i - 1];
while(j > 0 && str2[i] != str2[j])
{
j = Next[j - 1];
}
if(str2[i] == str2[j])
Next[i] = j + 1;
else
Next[i] = 0;
}
}
int kmp()
{
int len1 = strlen(str1), len2 = strlen(str2);
int i, j, ans = 0;
for(i = 0, j = 0; i < len1; i++)
{
while(j > 0 && str1[i] != str2[j])
{
j = Next[j - 1];
}
if(str1[i] == str2[j])
j++;
if(j == len2)
{
ans++;
j = Next[j - 1];//可重复的 比如 AZA
// AZAZAZA 输出3
// j = 0; 输出2 不可重复
}
}
return ans;
}
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
scanf("%s %s", str2, str1);
get_Next();
int v = kmp();
printf("%d\n", v);
}
}
自我感觉kmp真的很神奇,Next[i - 1] = x记录的是说第i个字符前x有个字符和前缀长度为x的匹配,这也就是为什么Next数组可以用来表示前后缀的匹配程度的原因了。
当进行匹配时,如果当前第x个不匹配了,就说明前x个已经是匹配的了。举个栗子,ababababc和ababc的匹配,ababc的Next是00120, 当c个第五个a不匹配了,就说明他们前四个是匹配的,这时Next[3]=2,说明ab和前缀ab是一样的,既然34位置上的ab可以和母串ab匹配,前缀的ab自然就可以,这样直接去比较abab*a*babc和abab*c* 就好啦,省了很多时间。本来kmp就是不想浪费之前已经匹配过的信息才加以优化的。