POJ 3461 Oulipo(kmp算法解析)

题目链接https://cn.vjudge.net/contest/320014#problem/F
Sample Input

3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN

Sample Output

1
3
0

翻译:每组数据两行字符串(原串和模拟串),求原串中有多少个模拟串?

KMP算法:
对于两个串,ps:BABABABCBABABABB和p:BABABB,求ps中有多少个p,常规方法如下,p串,一位一位的往后挪
在这里插入图片描述
对于KMP算法:
在这里插入图片描述

f(l)=k:l 位失配,回溯到k。(k为:前缀和后缀的最长匹配)。
分析:用一个数组记录:模拟串的每一位失配后(失配前的每一位都是匹配的),回溯到哪一位。比如第一次模拟串的最后一位B,和原串的第5位(下标从0开始)不匹配,那么模拟串就回溯到第3位(下标从0开始),和失配位置接着比较。可以看出模拟串第3位前面的都已经和原串相匹配

如何求数组(用next数组记录)?

i和j位上的字符是否相同:
1,不同,j=next[j](回溯到相同)
2,相同
next[i+1]=j+1;

 void solve(int len)
{
    int i=0,j=-1;//初始化
    next[0]=-1;
    while(i<len)
    {
        if(j<0||s[i]==s[j])
            next[++i]=++j;
        else
            j=next[j];
    }
}

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
char a[N],b[N];
int net[N];
void kmp(int len)/*只是对模拟串的操作,与主串无关*/
{
    net[0]=-1;
    int i=0,k=-1;
    while(i<len)
    {
        if(k<0||a[i]==a[k])
            net[++i]=++k;
        else
            k=net[k];
    }
    /*for(int i=0;i<len;i++)
        printf("%d ",net[i]);
    printf("\n");*/
}
int main()
{
    int T;
    scanf("%d",&T);

    while(T--)
    {
        scanf("%s%s",a,b);
        int len1=strlen(a);
        int len2=strlen(b);
        kmp(len1);//预处理出来net数组
        int sum=0,i=0,k=0;
        while(i<len2)
        {
            if(k<0||b[i]==a[k])
                i++,k++;
            else
                k=net[k];/*回溯到k位接着比较*/
            if(k==len1)
            {
                sum++;
                k=net[k];
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

重复是提高熟练度的唯一方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zaiyang遇见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值