KMP算法学习总结
一、为啥要烤馍片
幼稚(朴素)字符串匹配法的时间复杂度为O(n²),并且指示主串的指针要来回回溯,看起来非常的不聪明。此时采用KMP算法,应用next数组,使得指示主串的指针不进行回溯且将时间复杂度降为O(m+n) (写的有点粗略
二、求函数
1.求next数组
a)手动求的方法(适合模式串较短且在选择题中应用)
贴出来手写笔记
b)写成伪代码
思路:虚拟一个重复的模式串并定义next[j]=t;
情况① Pj == Pt 可以得知next[j+1] == t+1 == next[j+1]+1;
情况② Pj != Pt 可以把原模式串看成主串,重复的模式串看成模式串,即令 t=next[t]
若t==0 next(j+1) == 1
伪代码如下:
int getNext(char substr[],int next[])
{
int t=0;
int j=1;
next[1]=0;
while(j<strlen(substr))
{
if(t==0||substr[t]==substr[j])
{
++t;
++j;
next[j]=t;
}
else{
t=next[t];
}
}
}
c)nextval数组(欠佳
对于AAAAB这种模式串,如果在4号位置(下标从1)A不匹配,则3号,2号位置均不匹配,最终 j=0 考虑将j一步到位直接赋值为0
情况① j=1 nextval[j]=0
情况② j>1
若Pj != Pnext[j] nextval[j]=next[j]
若Pj = Pnext[j] nextval[j] = nextval[ next[j] ]
对next数组的伪代码进行修改可得:
int getNextval(char substr[],int nextval[],int next[])
{
int t=0;
int j=1;
next[1]=0;
nextval[1]=0;
while(j<strlen(substr))
{
if(t==0||substr[t]==substr[j])
{
next[j+1] = t+1;
if(substr(j+1) != substr[next[j+1]])
nextval[j+1] = next[j+1];
else
nextval[j+1] = nextval[next[j+1]];
++t;
++j;
}
else{
t=nextval[t];
}
}
}
2.烤馍片
很好理解,指针i,j分别指向主串和模式串下标为1的位置,j匹配到不匹配的地方就j = next[j] 进行回溯 看很多教材下标为0的位置都空出用来存串的长度或者啥的,但个人感觉输入上就有点问题了orz
直接上伪代码:
int KMP(char str[],char substr[])
{
int i = 1;
int j = 1;
int next[101];
getNext(substr,next);
while(i<=str.lenth && j<=substr.lenth)
{
if(j==0 || str[i]==substr[j])
{
i++;
j++;
}
else{
j=next[j];
}
}
if(j>strlen(substr))
return i-strlen(substr);
else return 0;
}
三、烤好了
C语言输入上有些问题,为了使下标从1开始存储,假设主串和模式串都是定长字符串…
源代码:
#include<stdio.h>
#include<string.h>
int getNext(char substr[],int next[])
{
int t=0;
int j=1;
next[1]=0;
while(j<strlen(substr))
{
if(t==0||substr[t]==substr[j])
{
++t;
++j;
next[j]=t;
}
else{
t=next[t];
}
}
}
int KMP(char str[],char substr[])
{
int i = 1;
int j = 1;
int next[101];
getNext(substr,next);
while(i<=6 && j<=2)
{
if(j==0 || str[i]==substr[j]){
i++;
j++;
}
else {
j=next[j];
}
}
if(j>2)
return i-2;
else return 0;
}
int main()
{
char str[101];
char substr[101];
int next[101];
int i;
for(i=1;i<=6;i++){
scanf("%s",&str[i]);
}
for(i=1;i<=2;i++){
scanf("%s",&substr[i]);
}
printf("%d",KMP(str,substr));
}
总结
nextval数组
输入问题