字符串匹配(2)

话说,如果普通的字符串匹配,朴素算法也就够用了。遇到image这种情况的话……不如倒着来朴素?(我喜欢乱搞……(逃
关于其他字符串匹配算法,请参见 字符串匹配(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;
}

 

posted on 2016-07-15 14:49  Chuckqgz  阅读(169)  评论(0编辑  收藏  举报

导航