字符串匹配(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;
}
浙公网安备 33010602011771号