P3375 【模板】KMP字符串匹配 (KMP模板)

题目描述

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

(如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。)

输入输出格式

输入格式:
第一行为一个字符串,即为s1

第二行为一个字符串,即为s2

输出格式:
若干行,每行包含一个整数,表示s2在s1中出现的位置

接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。

输入输出样例

输入样例#1:
ABABABC
ABA
输出样例#1:
1
3
0 0 1
说明

时空限制:1000ms,128M

数据规模:

设s1长度为N,s2长度为M

对于30%的数据:N<=15,M<=5

对于70%的数据:N<=10000,M<=100

对于100%的数据:N<=1000000,M<=1000000

思路:直接把s1接在s2后面进行KMP,枚举所有点若next[i]==s2.len则i是一个答案。
注意:串接时记得中间加一个符号防止影响结果(仔细想想)

代码注释:
1.字符串都以第0个开始
2.我这里的next[i]表示i点前面(不包含i)最长的前缀和后缀相同的字符串如:”abcabc”中 s[3]=’a’,next[3]=0,s[4]=’b’,next[4]=1(‘a’),s[5]=’c’,next[5]=2(“ab”)。
3.不明白KMP的可以尝试根据代码手算个数据体会一下(最好是画线段或矩形分情况思考一下),我不具体写了。

code1:

//By Menteur_Hxy
#include
#include
#include
#include
using namespace std;

const int MAX=100005;
int next[MAX];
char s[MAX],a[MAX];

int main() {
    scanf("%s",s+1);
    getchar();
    int len1=strlen(s+1);
    scanf("%s",a+1);
    int len2=strlen(a+1);
    int len=len2;
    a[++len]='*';
    for(int i=1;i<=len1;i++) 
        a[++len]=s[i];

    for(int i=2,j=0;i<=len;i++) {
        while(j && a[i]!=a[j+1]) j=next[j];
        if(a[i]==a[j+1]) j++;
        next[i]=j;
    }
    for(int i=1;i<=len;i++) if(next[i]==len2) printf("%d\n",i-2*len2);
    for(int i=1;i<=len2;i++) printf("%d ",next[i]);
    return 0;
}

code2:

//By Menteur_Hxy
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int MAX=1000005;
int next[MAX<<1];
string s1,s2;

int main() {
    cin>>s1;getchar();cin>>s2;
    int len1=s1.length();
    int len2=s2.length();
    int len3=len1+len2+1;
    s2+='#'+s1;//'#'即隔离符号
    next[0]=-1;
    int k=-1,j=0;
    while(j < len3) {
        if(k==-1 || s2[j]==s2[k]){//若k位于字符串首前或s[k]==s[j]显然有
            k++,j++;
            next[j]=k;
        }
        else k=next[k];//向前寻找一个小一点的但又可能满足条件的最大的
    }
    for(int i=0;iif(next[i]==len2) printf("%d\n",i-len2*2);
    for(int i=0;iprintf("%d ",next[i+1]);
    return 0;
}

你可能感兴趣的:(字符串-KMP,其他-模板)