ACM-字符串-KMP HDU4763 Theme Section 深刻理解next数组

KMP模板套了那么久,没真正理解next可不行!

string s;
next[i]:字符s[i] 与 (aaxoaaaaa)真前缀 失配时指向串的位置(跳转数组)
某种意义上:next[i]等于P[0]...P[i - 1]最长的相同真前后缀的长度
例如: a a x o a a a a a
next:-1 0 1 0 0 1 2 2 2
              * * *
*1:若这里的a失配之后指向s[0]:a
*2:若这里的a失配之后指向s[1]:a
*3:若这里的a失配之后指向s[2]:x

看了这么久,发现其实KMP就是固定起点(前缀)的字符串匹配,一定是要看前缀的。

==============分割线============

题意:给你一个母串:(子串)*(子串)*(子串),就是求一个最长的母串前缀(zilen),既出现在母串中间[zilen,mulen-zilen],又是母串的结尾
可以利用next跳转,
1.从最后面开始,j=len
2.那么处理的子串长度就是next[j](next数组一直到字符串结尾的后一位,因为这里才有产生失配)
3.一直递归等于j=next[j],直到j==-1结束

代码如下:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
const int maxn=1e6+100;
const int maxm=26000;
int nex[maxn];//next数组
//对母串生成next
void getnext(string s){
    memset(nex,0,sizeof(nex));
    int i=0;
    int j=-1;
    nex[0]=-1;
    int len=s.size();
    while(i<len){
        if(j==-1||s[i]==s[j])nex[++i]=++j;
        else j=nex[j];
    }
} 
//输入当前字符串,当前位置(前缀子串的长度),母串长度
bool subkmp(string s,int pos,int mulen){
    int j=0;
    for(int i=pos;i<mulen-pos;i++){
        while(j>0&&s[i]!=s[j])j=nex[j];
        if(s[j]==s[i])j++;
        if(j==pos)return true;
    }
    return false;
}
int main(){
    int t;
    string s;
    cin>>t;
    while(t--){
        cin>>s;
        int len=s.size();
        if(len<3)printf("0\n");
        else{
            getnext(s); 
            //for(int i=0;i<=len;i++)printf("%c     nex[%d]=%d\n",s[i],i,nex[i]);//可以输出查看next,慢慢理解
            int maxlen=0;
            int j=len;
            while(nex[j]>=0){//nex[j]指到后缀与前缀刚失配的位置,一直到-1 
                if(subkmp(s,nex[j],len)){
                    maxlen=max(maxlen,nex[j]);
                }
                j=nex[j];
            }
            if(maxlen)printf("%d\n",maxlen);
            else printf("0\n");
        }

    }
    return 0;
}

同类型题目:HDU2594

这里是KMP专题,大家可以自己VJ克隆了去写,有一些其实是后缀数组的,可以先不写
希望和大家一起共同进步!~再见~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值