KMP模式串匹配
查询在一个很长n的“文本串”中,给定的很短m的“模式串”的出现有无,次数,位置
复杂度O(n+m) 而不是暴力的O(n*m)
这里对模式串做了一个神奇的移位法则,注意KMP是只针对模式串的操作,不是文本串
我喜欢把kmp叫做“对应的前一项前缀位置”
例如:
KMP记录的是怎么一回事,看图看数据马上就明白了
123123123923123123 ----模式串
000123456000123456 ----对应KMP数组值
还有点模糊?
再来组数据
1231212312
0001212345
根据这两张图总结下:
1.由图二可知,匹配基数为字符串的所有前缀(12,123均为前缀)
2.由图一二对比发现,如果字符串出现与前缀中断匹配的部分,或者自己本身就是前缀的话,那么这些部分的KMP值全部为0
3.如果字符串与前缀匹配一直没有发生中断,那么当前位置KMP值可以承接为离自己最近的前缀KMP值
上代码:
char str[N]; cin>>str+1; int j=0; int len=strlen(str+1); For(i,2,len){ while(j&&str[i]!=str[j+1]) j=kmp[j]; //若发现自己后面的点无法匹配,那就跳为kmp值(前一个前缀值) if(str[i]==str[j+1]) j++;//直到有东西开始和前缀发生匹配 kmp[i]=j;//承接前一个前缀配对的位置或是指向0 }
接下来直接和文本串匹配其实跟模式串内部匹配没有实质区别:
char text[N]; cin>>text+1; j=0; for(int i=1;i<=strlen(text+1);i++) { while(j>0&&str[j+1]!=text[i]) j=kmp[j]; if (str[j+1]==text[i]) j++; if (j==len) { //长度符合就输出 cout<<i-len+1<<endl; j=kmp[j]; } }