第一行咕咕咕。
第二行—— %D.E.Knuth,J.H.Morris和V.R.Pratt(虽然我并不知道他们是谁
KMP:用于解决模式串匹配问题。即,给定一个字符串,找到这个字符串在给定的文本串中有没有出现,出现下标,出现次数等。
KMP的过程其实就是字符串不停匹配,相同两个位置的字符下标均++,不合适保持文本串不变,令模式串前跳,找到相同前缀的位置进行匹配。
next数组存的是到当前字符之前的字符串中,有相同长度的相同前缀的位置。所以可令初值为-1,求法思想其实仍为求相同前缀长度,但有-1作抵,即为其位置。
当前长度的字符串的所有的前缀后缀,最长相同前后缀的长度为:ex:ABABC,到ABAB时,其前缀为A,AB,ABA后缀为B,AB,BAB,最长长度即为2(AB)。
然后即可利用next数组,当字符串不匹配时,找到相同前缀在的位置,前跳到这里位,即可再次开始匹配。若为0/-1即前跳到开头,否则前跳next[j]个字符。
失配时,模式串向左移动的位数即为:其对应的next数组值(即为返回了相同前缀的位置)。
求next数组值:类似于kmp的匹配思想,令模式串自己匹配自己。
其他:时间复杂度为O(n+m)。n为模式串长度,m为文本串长度。
我现在学的所有算法,我都觉得过程真通俗易懂,实现起来真一点也看不懂。其实还是我不够懂。
本代码以洛谷P3375为例
#include<bits/stdc++.h>
#define ll long long
#define maxn 1000005
using namespace std;
int le,len;
int ne[maxn];
void kmp(char *c1,char *c2)
{
int i = 0;
int j = 0;//从两个字符串起始开始匹配
while(i < le)
{
if(ne[j] == -1 || c1[i] == c2[j])
i++,j++;
else
j = ne[j];//失配返回
if(j == len)
printf("%d\n",i-j+1),j = ne[j];
}//i-j+1为文本串中模式串出现的位置
}//j为回到有相同前缀的模式串字串的位置
void chuli(char* c2)
{
int k = -1;
int j = 0;
while (j < len)
{
if (k == -1 || c2[j] == c2[k])
{
++k;
++j;
ne[j] = k;
}
else
{
k = ne[k];//失配则回到上一个相同的地方
}
}
}
int main()
{
char c1[maxn],c2[maxn];
scanf("%s",c1);
scanf("%s",c2);
memset(ne,-1,sizeof(ne));
le = strlen(c1);
len = strlen(c2);
chuli(c2);
kmp(c1,c2);
for(int i = 1; i <= len; ++i)
{
if(i == 1)
printf("%d",ne[i]);
else
printf(" %d",ne[i]);
}
return 0;
}
欢迎指出错误qwq。
我感觉我自己写的思路很乱qwq