zoukankan      html  css  js  c++  java
  • 扩展KMP(讲解+模版+例题)

    在阅读这篇文章之前,我们假定你已经掌握了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;
    }
    
  • 相关阅读:
    Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
    Educational Codeforces Round 89 (Rated for Div. 2) E. Two Arrays
    Educational Codeforces Round 89 (Rated for Div. 2) D. Two Divisors
    Codeforces Round #647 (Div. 2) E. Johnny and Grandmaster
    Codeforces Round #647 (Div. 2) F. Johnny and Megan's Necklace
    Codeforces Round #648 (Div. 2) G. Secure Password
    Codeforces Round #646 (Div. 2) F. Rotating Substrings
    C++STL常见用法
    各类学习慕课(不定期更新
    高阶等差数列
  • 原文地址:https://www.cnblogs.com/sz-wcc/p/11331361.html
Copyright © 2011-2022 走看看