KMP算法

 
#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
#define inf 0x3fffffff
int Next[maxn];
string s1,s2;
int m,n;
void buildNext(){
    Next[0]=-1;
    int i;
    for(int j=1;j<m;j++){
        i=Next[j-1];//存储最大前缀的最后一个值的下标
        while((i>=0)&&(s2[i+1]!=s2[j])){//若当前前缀不符合,则回退,找寻次大的前缀
            i=Next[i];
        }
        if(s2[i+1]==s2[j]){
            Next[j]=i+1;
        }
        else{//i<0,不存在前缀
            Next[j]=-1;
        }
    }
}

int main(){
    cin>>s1>>s2;
    n=s1.length();
    m=s2.length();
    buildNext();
    int i=0,j=0;
    while(i<n&&j<m){
        if(s1[i]==s2[j]){
            i++;
            j++;
        }
        else if(j>0){
            j=Next[j-1]+1;
        }
        else{
            i++;
        }
    }
    if(j==m){
        cout<<i-m<<endl;
    }
    else{
        cout<<-1<<endl;
    }
    return 0;
}

理解:

KMP思想:配对不成功时,将最大前缀与后缀对齐,从而减少匹配次数。

 

 

next数组的作用:配对不成功时,子串指针移动到最大前缀的最后一个值的下一个位置,就是next的值。

 

int buildNext(){
    Next[0]=-1;
    int i;
    for(int j=1;j<m;j++){
        i=Next[j-1];//存储最大前缀的最后一个值的下标
        while((i>=0)&&(s2[i+1]!=s2[j])){//若当前前缀不符合,则回退,找寻次大的前缀
            i=Next[i];
        }
        if(s2[i+1]==s2[j]){
            Next[j]=i+1;
        }
        else{//i<0,不存在前缀
            Next[j]=-1;
        }
    }
}

递推方式求解next,如下图:如果在j-1配对的基础上,如果match[j-1]+1与j的字符相等,则可以直接:match[j]=match[j-1]+1  (可以通过反证法证明)

如果不相等,则讲 i 回退,找次小的前缀。while里面是前缀递减的过程

 

posted @ 2021-03-31 22:59  XA科研  阅读(49)  评论(0编辑  收藏  举报