KMP浅谈

基本思想

编辑
设主串(下文中我们称作T)为:a b a c a a b a c a b a c a b a a b b
模式串(下文中我们称作W)为:a b a c a b
用暴力算法匹配字符串过程中,我们会把T[0] 跟 W[0] 匹配,如果相同则匹配下一个字符,直到出现不相同的情况,此时我们会丢弃前面的匹配信息,然后把T[1] 跟 W[0]匹配,循环进行,直到主串结束,或者出现匹配成功的情况。这种丢弃前面的匹配信息的方法,极大地降低了匹配效率。
而在KMP算法中,对于每一个模式串我们会事先计算出模式串的内部匹配信息,在匹配失败时最大的移动模式串,以减少匹配次数。
比如,在简单的一次匹配失败后,我们会想将模式串尽量的右移和主串进行匹配。右移的距离在KMP算法中是如此计算的:在 已经匹配的模式串子串中,找出最长的相同的 前缀后缀,然后移动使它们重叠。
在第一次匹配过程中
T: a b a c a  a b a c a b a c a b a a b b
W: a b a c a  b
在T[5]与W[5]出现了不匹配,而T[0]~T[4]是匹配的,现在T[0]~T[4]就是上文中说的 已经匹配的模式串子串,现在移动找出 最长的相同的前缀和后缀并使他们重叠:
T: a b a c a a b a c a b a c a b a a b b
W: a  b a c a  b
然后在从上次匹配失败的地方进行匹配,这样就减少了匹配次数,增加了效率。
然而,如果每次都要计算 最长的相同的前缀反而会浪费时间,所以对于模式串来说,我们会提前计算出每个匹配失败的位置应该移动的距离,花费的时间就成了常数时间。

NEXT数组:

         两张图:


模板:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <queue>
#include <deque>
#include <stack>

using namespace std;
typedef long long ll;
const int maxn = 1000000+5;
int next[maxn];
char s[maxn],a[maxn];
void cal_next(char *a){
    memset(next,-1,sizeof(next));
    int len = strlen(a);
    int k = -1 ;
    next[0]=-1;
    for(int p = 1 ; p < len ; p++){
        while(k>-1&&a[p]!=a[k+1]) k = next[k];
        if(a[k+1]==a[p]) next[p]=++k;
    }
}
int kmp(char *s,char *a){
    int slen = strlen(s);
    int alen = strlen(a);
    int k = -1;
    for(int i = 0 ; i < slen ; i++){
        while(k>-1&&a[k+1]!=s[i]) k = next[k];
        if(a[k+1]==s[i]) k++;
        if(k == alen - 1){
            return i;
        }
    }
    return 0;
}
int main(){
    int kase;
    scanf("%d",&kase);
    while(kase--){
        scanf("%s",a);
        scanf("%s",s);
        cal_next(a);
        printf("%d\n",kmp(s,a));
    }
}

其他的回来补坑。。。

猜你喜欢

转载自blog.csdn.net/insist_77/article/details/80090734
kmp