KMP算法复习笔记

it2022-05-05  118

KMP 算法

KMP 算法是一种改进的字符串匹配算法,KMP 算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度 O ( m + n ) O(m+n) O(m+n)

朴素做法

你有两个串 ababbaba、aba,求第二个串在第一个串中出现了多少次。

设两串的长度分别为 n , m n,m n,m,则时间复杂度 O ( n m ) O(nm) O(nm)

我们看到,标 ☆ 的几步可以优化。那应该怎么优化呢?

next 数组

我们发现,当一个串匹配失败时,不总是需要再次从头开始匹配。如果这个串有公共的前后缀,那么可以节约时间。

那我们就在这方面下点功夫。设 n e x t [ x ] next[x] next[x] 表示这个串前 x x x 位的公共的前后缀的最大长度,且 n e x t [ x ] < x next[x]<x next[x]<x x ∈ [ 1 , l e n ] x\in[1,len] x[1,len] l e n len len 表示这个串的长度。

以下为求 n e x t next next 数组的步骤。 定义两个指针 i = 2 , j = 0 i=2,j=0 i=2,j=0。 因为 s t r [ i ] ≠ s t r [ j + 1 ] str[i]\neq str[j+1] str[i]̸=str[j+1],且 j = 0 j=0 j=0,所以 n e x t [ i ] = n e x t [ 2 ] = 0 next[i]=next[2]=0 next[i]=next[2]=0。 因为 s t r [ i ] = s t r [ j + 1 ] str[i]=str[j+1] str[i]=str[j+1],匹配成功。所以将 j j j 指针右移一位, n e x t [ i ] = j + 1 next[i]=j+1 next[i]=j+1

匹配成功, j j j 右移一位。

匹配失败,令 j = n e x t [ j ] j=next[j] j=next[j],继续判定。

仍然无法配对。因此 n e x t [ i ] = 0 next[i]=0 next[i]=0

luogu P3375

#include<cstdio> #include<cstdlib> #include<cstring> #define reg register int next[1000010]; char str1[1000010],str2[1000010]; int len1,len2,t=0; int main(){ memset(next,0,sizeof(next)); scanf("%s%s",str1+1,str2+1); len1=strlen(str1+1);len2=strlen(str2+1); for(reg int i=2;i<=len2;++i){ while(t>0&&str2[t+1]!=str2[i]) t=next[t]; if(str2[t+1]==str2[i]) ++t; next[i]=t; } t=0; for(reg int i=1;i<=len1;++i){ while(t>0&&str2[t+1]!=str1[i])t=next[t]; if(str2[t+1]==str1[i]) ++t; if(t==len2) printf("%d\n",i-t+1); } for(reg int i=1;i<=len2;++i) printf("%d ",next[i]); }

loj 10043

#include<cstdio> #include<cstdlib> #include<cstring> #define reg register char str[1010],s[1010]; int next[1010]; int t=0,l,len; int ans; int main(){ do{ scanf("%s",str+1); if(str[1]=='#'&&str[2]=='\0') break; scanf("%s",s+1); l=strlen(str+1);len=strlen(s+1); memset(next,0,sizeof(next)); t=ans=0; for(int i=2;i<=len;++i){ while(t>0&&s[t+1]!=s[i]) t=next[t]; if(s[t+1]==s[i]) ++t; next[i]=t; } t=0; for(int i=1;i<=l;++i){ while(t>0&&s[t+1]!=str[i]) t=next[t]; if(s[t+1]==str[i]) ++t; if(t==len) ++ans,t=0; } printf("%d\n",ans); }while(1); }

最新回复(0)