KMP
我都初三了还不会KMP……
全称The Knuth-Morris-Pratt Algorithm,三个大佬同时发明
只适用于单模匹配,可以求子串在母串中出现的位置、次数等东西
普通匹配是失配了重新从母串下一位、子串第一位开始匹配,最坏时间复杂度 O(nm) O ( n m )
KMP K M P 思想核心是建立 next n e x t 数组,利用失配信息快速匹配,最坏时间复杂度 O(n) O ( n )
next
网上其他教程写next写的跟sh*t一样
我写简单一点,对于子串的每一位建 next n e x t
- 第 i i 位的 next n e x t 表示以 i i 为结尾的最长的、且从第一位字符开始存在的字符串的末尾位置
这个可以子串自己和自己匹配实现
如果当前建 next n e x t 到第 i i 位,看一下 next[i]+1 n e x t [ i ] + 1 位和 i+1 i + 1 相不相同
相同的话 next[i+1]=next[i]+1 n e x t [ i + 1 ] = n e x t [ i ] + 1 ,否则 i=next[i] i = n e x t [ i ] 重新回溯做
(大概像把 i+1 i + 1 的 next n e x t 再指向 next n e x t 的 next n e x t ,有点像 AC A C 自动机)
所以next是往前跳的为什么叫做next
匹配
搞完 next n e x t ,匹配很简单
设 i,j i , j 分别是母串、子串匹配到了哪一位
如果 i,j i , j 位置不匹配就 j=next[j] j = n e x t [ j ] ,否则 i++,j++ i + + , j + +
当 j==len子串 j == l e n 子 串 ,就匹配成功一次
多次匹配就继续做 KMP K M P 直到 i i 指针 ==len母串 == l e n 母 串
code
- 丢个模板
#include<stdio.h>
#include<string.h>
#define MAXN 100005
using namespace std;
char s1[MAXN],s2[MAXN];
int len1,len2,i,j,k;
int next[MAXN];
void init()
{
k=-1,j=0;
next[0]=-1;
while (j<len2)
{
if (k==-1 || s2[k]==s2[j])
{
j++;
k++;
next[j]=k;
}
else k=next[k];
}
}
void kmp()
{
j=0;
while (i<len1 && j<len2)
{
if (j==-1 || s1[i]==s2[j])i++,j++;
else j=next[j];
}
if (j==len2)printf("%d\n",i-j+1);
}
int main()
{
scanf("%d%d",&len1,&len2);
scanf("%s%s",s1,s2);
init();
kmp();
while (1)
{
if (i==len1) break;
i=i-j+2;
kmp();
}
return 0;
}