KMP

作用是找大串里匹配的小串的位置

理解好难,先讲一下原理。找目前字符串的Border:是一个字符串最长的,能跟真后缀相同的真前缀的长度。

比如ABCDABCD

从1号到八号 Border分别是00001234.。

如何求Border:

我们以ABABAC为例

用肉眼明显知道

001230

我们知道如果前面的字符串对称,只需要把当前字符和前面字符对称总数+1比较,如果继续对称,那么对称总数+1,否则

我们回到F[前一个总对称数]+1,这个字符比较,如果相等,下次比较则比较这个字符串的下一个即刻,如果依然不等,继续上述操作直到起点。

感觉没讲得很清楚,看了一位大佬的博客,理解了一点,结合学长的代码,模拟了一下。

https://blog.csdn.net/u011564456/article/details/20862555

大佬链接。

求出了Border.。我们需要利用Border进行优化匹配。

还是刚才那个道理,匹配字符看Boeder,即看是否有无效的匹配。

ABCBABCAAB

ABCAA

匹配到第4个就无法匹配了,我们此时可以利用Boeder,直接移动三位而不是一位。

从而产生优化的效果。

 

例如:

学长的例子

P=ABCDABD

T=ABCABCDABABCDABCDABDE

T的第一个位置开始匹配

 

123456789012345678901

ABCABCDABABCDABCDABDE

ABCDABD

1234567

 

P的第4个字符匹配失败!

我们到此成功匹配到了P3个字符,而F[3]=0

- 所以也无法在??T_2, ?? T_3处继续产生匹配;

P串向右移动k-F[k]=3个字符

 

123456789012345678901

ABCABCDABABCDABCDABDE

ABCDABD

1234567

我们到此成功匹配到了P3个字符,而F[3]=0

- 所以也无法在??T_2, ?? T_3处继续产生匹配;

P串向右移动k-F[k]=3个字符

 

123456789012345678901

ABCABCDABABCDABCDABDE

                       ABCDABD

 1234567

此时我们需要移动4而不是6.

我们可以知道F[6]=2;

即移动k-F[k]=4;

 

 

#include <bits/stdc++.h>
using namespace std;
const int maxn=1000050;
int F[maxn];
char P[maxn],T[maxn];
void getF(char *P,int m) {
    F[1]=0;
    for(int i = 2; i <= m; ++i) {
        int k=F[i-1];
        while(k&&P[k+1]!=P[i]) k=F[k];
        if(P[k+1]==P[i]) ++k;
        F[i]=k;
    }
}
void getMatch(char *P,int m,char *T,int n)
{
    getF(P,m);
    int k=0;
    for(int i = 1; i <= n; ++i) {
        while(k&&T[i]!=P[k+1]) k=F[k];
        if(T[i]==P[k+1]) ++k;
        if(k==m) {
            printf("matched at %d\n", i-m+1);
            k=F[k];
        }
    }
}
int main() {
    scanf("%s%s", T+1,P+1);
    getMatch(P,strlen(P+1),T,strlen(T+1));
    return 0;
}

 

学长的代码。镇楼。

posted on 2019-01-15 22:27  湫叶  阅读(124)  评论(0编辑  收藏  举报

导航