ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

扩展KMP(讲解+模版+例题)

2019-08-10 13:50:31  阅读:329  来源: 互联网

标签:cnt last extend 模版 ll next KMP 例题 first


在阅读这篇文章之前,我们假定你已经掌握了KMP:n+1次探里的定义。

引入:扩展KMP是干什么的

扩展KMP解决的是源串S的每一个后缀与模式串P的最长公共前缀的长度的问题,并求解出答案extend数组,例如,ababac与aba的extend数组是3 0 3 0 1 0,这里extend[i]表示s[i:5](i从0开始)与p[0:2]的最长公共前缀的长度。

next数组的定义

这里的next数组与KMP里的不同。

next[i]表示从i开始的p的后缀与p的最长公共前缀的长度,也就是,p对p求扩展KMP,可以参见2019 Multi-University Training Contest 5 - 1006 - string matching

我们先假设已经有了next数组,来求extend,因为next数组的求法是和extend一样的。

扩展KMP

递推:已知extend[i-1],如何求extend[i]?

我们假设在前面匹配时,向右匹配到的最远坐标为last,是从first开始匹配的,也就是说s[first:last]=p[0:last-first]。可以推出s[i:last]=p[i-first:last-first],但这个不是和p的开头匹配,还不能用,我们取extend[i]=min(last-i+1, next[i-first]),看看p[i-first:last-first]和p开头有多少相同。然后向后检测extend[i]能不能更大,这一块暴力,别忘了最后更新first和last。

初始:暴力大法好

暴力检测s和p最大公共前缀长度extend[0]。

求next数组

和上面一样。next的0位置必定是p的长度,代码中last初值设为0是为了避免初始化。

例题

hdu2328

给一堆字符串,求最长公共字串。

找一个最短的串,暴力求出每一个后缀,和所有串匹配,找到每个extend里最大的,取总体最小,是一个答案,找到所有答案里长度最长的字典序最小的,就是答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<string>
#include<iostream>
#define ll long long
#define db double
#define ioss ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
int n,cnt;
ll ext[220],nex[220];
string skr[4020];
string ans[4020];
void getNext(string &strp,ll nextt[]){
    ll pl=strp.size();
    ll fir=0,las=0;
    nextt[0]=pl;
    for(ll i=1;i<pl;i++) {
        nextt[i] = min(las - i + 1, nextt[i - fir]);
        if (nextt[i] < 0) nextt[i] = 0;
        while (i+nextt[i]<pl && strp[nextt[i]] == strp[i + nextt[i]]) {
            nextt[i]++;
        }
        if (i + nextt[i] - 1 > las) {
            las = i + nextt[i] - 1;
            fir = i;
        }
    }
}
void exKMP(string &strp,string &strs,ll nextt[],ll extt[]){
    //cout<<"start exKMP:"<<endl;
    getNext(strp,nextt);
    ll pl=strp.size(),sl=strs.size();
    ll fir=0,las=-1,mnl=min(sl,pl);
    //cout<<strp<<endl<<strs<<endl;
    while(las<mnl-1&&strp[las+1]==strs[las+1]){
        las++;
        //cout<<"init++"<<endl;
    }
    extt[0]=las+1;
    for(ll i=1;i<sl;i++){
        extt[i]=min(las-i+1,nextt[i-fir]);
        if(extt[i]<0) extt[i]=0;
        while(extt[i]<pl && i+extt[i]<sl && strp[extt[i]]==strs[i+extt[i]]){
            extt[i]++;
        }
        if(i+extt[i]-1>las){
            las=i+extt[i]-1;
            fir=i;
        }
    }
}
int main() {
    //ioss;
    //freopen("1.in","r",stdin);
    //freopen("2.out","w",stdout);
    while(scanf("%d",&n)==1&&n){
        cnt=0;
        int mnlen=300,mnlenx;
        for(int i=1;i<=n;i++) {
            cin >> skr[i];
            if (skr[i].size() < mnlen) {
                mnlen = skr[i].size();
                mnlenx = i;
            }
        }
        for(int i=0;i<skr[mnlenx].size();i++){
            ll mn=1e10;
            string cur=skr[mnlenx].substr(i);
            //out<<i+1<<": cur= "<<cur<<endl;
            for(int j=1;j<=n;j++){
                ll mx=0;
                exKMP(cur,skr[j],nex,ext);
                /*cout<<"nex: ";
                for(int k=0;k<cur.size();k++){
                    cout<<nex[k]<<' ';
                }
                cout<<endl;
                cout<<"ext: ";*/
                for(int k=0;k<skr[j].size();k++){
                    //cout<<ext[k]<<' ';
                    mx=max(mx,ext[k]);
                }
                //cout<<endl;
                mn=min(mn,mx);
                //cout<<"mn = "<<mn<<endl;
            }
            if(mn>0){
                if(cnt==0||(mn==ans[1].size())){
                    ans[++cnt]=cur.substr(0,mn);
                }
                else if(mn>ans[1].size()){
                    cnt=0;
                    ans[++cnt]=cur.substr(0,mn);
                }
            }
        }
        if(cnt){
            sort(ans+1,ans+1+cnt);
            cout<<ans[1]<<endl;
        }
        else cout<<"IDENTITY LOST"<<endl;
    }
    return 0;
}

标签:cnt,last,extend,模版,ll,next,KMP,例题,first
来源: https://www.cnblogs.com/sz-wcc/p/11331361.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有