字符串匹配(2)
话说,如果普通的字符串匹配,朴素算法也就够用了。遇到这种情况的话……不如倒着来朴素?(我喜欢乱搞……(逃
关于其他字符串匹配算法,请参见 字符串匹配(1) ,本篇重点介绍KMP算法。
Knuth-Morris-Pratt算法
这种算法的预处理时间复杂度为O(m),匹配时间为O(n),相比上一种算法,这种算法少了一个|Sigma|的时间。
下面的内容可能并不清晰,我写出来只是做一个总结。这里(Matrix67)的介绍更为详尽。
我们假设T=abcdefghij…,P=abce
显然,在朴素算法的情况下,从T[1]匹配到T[4](从1开始计数),发现 大変、無理です 于是尝试从T[2]开始,从T[3]开始,从T[4]开始。
但是,从T[i]开始的前提条件是P[1]=T[i],显然,T[1]==P[1]!=P[2]!=P[3]!=P[4],既然这样,从T[2],T[3],T[4]开始尝试,都是无用功。
那我们继续假设T=ababcdefghij…,P=ababe
从T[1]开始匹配,到T[5]发现匹配失败,此时并不需要从T[2]开始匹配,而应该从T[3]开始。因为P[1..2]==P[3..4]==ab,而到T[5]匹配失败的同时,也说明了T[1..2]==T[3..4]==ab,因此继续让P[1..2]和T[3..4]配对即可
如此往复,我们发现具体从哪匹配,只取决于P,和T无关,因此引入一个数组,就是恶名昭著的next[]。
以下只贴出代码,具体内容请参见其他资料。代码是hzwer学长写的,参见这里
#include<cstdio> #include<string> #include<iostream> using namespace std; int p[101]; int main() { string a,b; cin>>a>>b; int n=a.length(),m=b.length(); a=" "+a;b=" "+b; int j=0; for(int i=2;i<=m;i++) { while(j>0&&b[j+1]!=b[i])j=p[j]; if(b[j+1]==b[i])j++; p[i]=j; } j=0; for(int i=1;i<=n;i++) { while(j>0&&b[j+1]!=a[i])j=p[j]; if(b[j+1]==a[i])j++; if(j==m){printf("%d",i-m+1);break;} } return 0; }