HihoCoder - 1015 KMP算法

题目链接

题意:一共c组数据,每组数据有两个字符串,求第一个字符串在第二个字符串中出现的次数。

思路:kmp模板题

kmp:相较于n*m的字符串匹配算法每次匹配失败后是一位一位移动模式串,kmp就相当于是一次多位的移动模式串par。

每次匹配失败移动位数的依据则是依靠next数组存储。


next[i]=max(0<=k<i,par[1 ... k]==par[i-k+1 ... i])若k=0则字符串为空。

next的求法:当我们已知next[1]到next[i-1]时,要求next[i]。

设next[0]=-1。根据next的定义,则par[i]=par[next[i]],而par[1 ... next[j]]==par[i-next[j] ... i-1](1<=j<i)。

那么如何快速求j?每次匹配par[1 ... i-1]和par[1 ... i]。j=next[i-1]。若par[j+1]!=par[i]则j=next[j]。

每次循环就相当于找一个j,有par[1 ... j]==par[i-j ... i-1],如此往复,直到有解或者j=-1。那么next[i]=j+1。


next的用法:与求法一致,只不过现在是用模式串par和原串ori进行匹配。设par下标为i,ori下标为j。

  1. 循环直到par[i+1]!=ori[j+1]。
  2. 若i+1>par的长度则匹配成功sum++,i=next[i],否则匹配失败。
  3. 若j+1>ori的长度则退出循环。
  4. 循环i=next[i]直到par[i+1]==ori[j+1]或者i==-1。
  5. 若i==-1则说明ori[j]已不存在解。则++i,++j。
  6. 若j<ori的长度则返回步骤1。
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
#define NUM 11000
string ori,par,s;
int c;
int ans;
int _next[NUM];
int getnext(int x)//求next数组
{
    int i;
    i=_next[x];
    while(i!=-1&&par[i+1]!=par[x+1])
        i=_next[i];
    return i+1;
}
int solve()//计数
{
    int i=0;
    int j=0;
    int cou=0;
    while(j<ori.size())
    {
        while(i+1<par.size()&&j+1<ori.size()&&ori[j+1]==par[i+1])
        {
            ++i;
            ++j;
        }
        if(i+1==par.size())++cou;
        if(j+1==ori.size())break;
        while(i+1==par.size()||(i!=-1&&par[i+1]!=ori[j+1]))
            i=_next[i];
        if(i==-1)
        {
            ++j;
            ++i;
        }
    }
    return cou;
}
int main()
{
    scanf("%d",&c);
    _next[0]=-1;
    _next[1]=0;
    while(c--)
    {
        par=ori=" ";
        cin>>s;
        par+=s;
        cin>>s;
        ori+=s;
        for(int i=2;i<par.size();++i)
            _next[i]=getnext(i-1);
        ans=solve();
        printf("%d\n",ans);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值