• KMP算法入门题集


    POJ  2406

    题意:求最长循环节

    题解:Next数组的使用,判断 len/ (len-Next[len]), 注意Next[] != 0要特别判断一下; 

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int maxn=1e6+5;
    int Next[maxn], m, n;
    char x[maxn], y[maxn];
    
    
    void KMP_Pre()
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        //freopen("in.txt", "r", stdin);
        while(cin>>x, x[0]!='.')
        {
            m=strlen(x);
            int ans=1;
            KMP_Pre();
            if(m%(m-Next[m])==0)
                ans=m/(m-Next[m]);
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    HDU 3746

    题意: 补齐循环节,求最少添加多少个字符,能获得循环节

    题解:画个图看看就行了,可发现 (len+x)/ (len+x-(Next[len] +x)) 注意Next[] != 0要特别判断一下;

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int maxn=1e6+5;
    int Next[maxn], m, n;
    char x[maxn], y[maxn];
    
    
    void KMP_Pre()
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        //freopen("in.txt", "r", stdin);
        int T; cin>>T;
        while(T--)
        {
            cin>>x;
            m=strlen(x);
            KMP_Pre();
            int ans;
            if(Next[m]!=0 && m%(m-Next[m])!=0)
                ans=(m-Next[m])-m%(m-Next[m]);
            else if(Next[m]==0)
                ans=m;
            else
                ans=0;
            cout<<ans<<endl;
        }
        return 0;
    }
    View Code

    HDU 1358

    题意:求前缀的循环节

    题解:和前面一样直接判断取余后是否有余数即可

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int maxn=1e6+5;
    int Next[maxn], m, n;
    char x[maxn], y[maxn];
    
    void KMP_Pre()
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    int main()
    {
        ios::sync_with_stdio(false);
        //freopen("in.txt", "r", stdin);
        int kase=0;
        while(cin>>m, m)
        {
            cin>>x;
            KMP_Pre();
            printf("Test case #%d
    ", ++kase);
            for(int i=2; i<=m; i++)
            {
                if(Next[i]>0 && i%(i-Next[i])==0)
                    printf("%d %d
    ", i, i/(i-Next[i]));
            }
            printf("
    ");
        }
        return 0;
    }
    View Code

    HDU 2087 

    题意:求子串在母串出现的次数(不重叠)

    题解:每次匹配完成后讲j指向0即可

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int maxn=1e5+5;
    int Next[maxn], m, n;
    char x[maxn], y[maxn];
    
    
    void KMP_Pre()
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    int KMP_Count()
    {
        int i=0, j=0;
        int ans=0;
        KMP_Pre();
        while(i<n)
        {
            while(j!=-1 && y[i]!=x[j])
                j=Next[j];
            i++; j++;
            if(j>=m){
                ans++; j=0;
            }
        }
        return ans;
    }
    
    
    int main()
    {
        ios::sync_with_stdio(false);
        //freopen("in.txt", "r", stdin);
        while(cin>>y>>x, y[0]!='#')
        {
            m=strlen(x);
            n=strlen(y);
            cout<<KMP_Count()<<endl;
        }
        return 0;
    }
    View Code

    POJ 2752 

    题意:求既是前缀又是后缀的子串长度 ; 

    题解:这题比之前的要难一点,这个是非常清晰Next数组和KMP算法的过程; 

    Next数组记录的就是前缀串,若Next[len]==s[len-1] 即前后缀相等,然后不断迭代Next[len]并判断即可,然后判断s[next[next[n-1]]] == s[n-1]是否成立,这样一直回滚,直到next[next[.....next[n-1]]] == -1为止。

    #include <cstring>
    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int maxn=1e6+5;
    int Next[maxn], m, n;
    char x[maxn], y[maxn];
    
    
    void KMP_Pre()
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    int ans[maxn];
    int main()
    {
        ios::sync_with_stdio(false);
        //freopen("in.txt", "r", stdin);
        while(cin>>x)
        {
            m=strlen(x);
            KMP_Pre();
            int pre=m-1, cnt=1;
            while(pre!=-1)
            {
                if(x[pre]==x[m-1])
                    ans[cnt++]=pre+1;
                pre=Next[pre];
            }
    
            while(--cnt)
                cout<<ans[cnt]<<" ";
            cout<<endl;
        }
        return 0;
    }
    View Code

    POJ 3080

    题意:找多个串之间的公共子串,输出最大的(数据量很小)

    题解:暴力截取+KMP匹配判断,维护一个最大的即可; 

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <string>
    using namespace std;
    
    string str[100], s[100];
    int Next[100];
    
    void KMP_Pre(string x, int m)
    {
        int i=0, j=-1;
        Next[0]=-1;
        while(i<m)                           // 这个之前错写成j<m
        {
            while(j!=-1 && x[i]!=x[j])
                j=Next[j];
            Next[++i]=++j;
        }
    }
    
    bool KMP(string x, int m, string y, int n)
    {
        //KMP_Pre(x, m);
        int i=0, j=0;
        while(i<n)
        {
            while(j!=-1 && y[i]!=x[j])
                j=Next[j];
            ++i; ++j;
            if(j>=m)
                return true;
        }
        return false;
    }
    
    int main()
    {
        //freopen("in.txt", "r", stdin);
        
        int T; cin>>T;
        while(T--)
        {
            int num; cin>>num;
            for(int i=0; i<num; i++)
                cin>>str[i];
    
            string ans="";
            for(int len=1; len<=str[0].size(); len++)         //这个等于之前丢了...        
                for(int i=0; i+len<=str[0].size(); i++)
                {
                    bool flag=1;
                    string p=str[0].substr(i, len);
                    KMP_Pre(p, p.size());
                    for(int k=1; k<num; k++)
                        if( !KMP(p, p.size(), str[k], str[k].size()) ){
                            flag=0; break;
                        }
                    if(flag)
                    {
                        if(ans.size()<p.size())
                            ans=p;
                        else if(ans.size()==p.size())
                            ans=min(ans,p);                    
                    }
                }
            if(ans.size()<3)
                cout<<"no significant commonalities"<<endl;
            else
                cout<<ans<<endl;
    
        }
        return 0;
    }
    View Code
  • 相关阅读:
    TensorFlow gfile文件操作详解
    ROS学习之日志消息
    typeid().name()获取类型名
    Ubuntu Qt配置QVTKWidget控件
    python-pcl简易文档(不包含自建函数与pcl_grabber包)
    ros源码之初始化函数init()调用的几个初始化函数
    奇异值分解(SVD)原理
    ROS节点的初始化及退出详解(ros::init、SIGINT、ros::ok、ros::NodeHandle)
    ROS Nodehandle句柄
    C++可变参数模板
  • 原文地址:https://www.cnblogs.com/Yokel062/p/10826967.html
Copyright © 2020-2023  润新知