kmp算法

给出两个字符串 s1​ 和 s2​,若 s1​ 的区间 [l,r] 子串与 s2​ 完全相同,则称 s2​ 在s1​ 中出现了,其出现位置为 l。
现在请你求出 s2​ 在 s1​ 中所有出现的位置。

定义一个字符串 s 的 border 为 s 的一个非 s 本身的子串 t,满足 t 既是 s 的前缀,又是 s 的后缀。
对于 s2​,你还需要求出对于其每个前缀 ′s′ 的最长 border ′t′ 的长度。

输入格式

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

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序输出 s2​ 在 s1​ 中出现的位置。
最后一行输出 ∣s2​∣ 个整数,第 i 个整数表示 s2​ 的长度为 i 的前缀的最长 border 长度。

输入输出样例

输入 

ABABABC
ABA

输出 

1
3
0 0 1 
KMP 的精髓在于,对于每次失配之后,都不会从头重新开始枚举,而是根据已知的数据,从某个特定的位置(与后缀对应的前缀)开始匹配;而对于模式串的每一位,都有唯一的前缀,这个在失配之后的位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间。

如abcdabaadc

abaac

当c与d不对应时将首端的a与d前的a进行对应而不是从头匹配

#include<iostream>
#include<cstring>
#define MAXN 1000010//定义MAXN方便后续更改
using namespace std;
int kmp[MAXN];
int la,lb,j;
char a[MAXN],b[MAXN];
int main()
{
    cin>>a+1;//从a[1]开始输入便于计算
    cin>>b+1;
    la=strlen(a+1);
    lb=strlen(b+1);
    for (int i=2;i<=lb;i++)
       {
       while(j&&b[i]!=b[j+1])
        j=kmp[j];
       if(b[j+1]==b[i])
       {
        j++;
        kmp[i]=j;
       }
       }//对于lb上每个字符做上标记,前后缀字符具有关系
    j=0;
    for(int i=1;i<=la;i++)
       {
          while(j>0&&b[j+1]!=a[i])//如果lb与la不相等,则将j调整到前缀位置,诺不相等则调整到首位
           j=kmp[j];
          if (b[j+1]==a[i])
           j++;
          if (j==lb)
          {
            cout<<i-lb+1<<endl;//i-lb+1为题目所求L
          j=kmp[j];//将j调整到字符串末尾左侧第一个相等处
          }
       }

    for (int i=1;i<=lb;i++)
    cout<<kmp[i]<<" ";
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值