• KMP 知识点整理


    1.扩展KMP

    2.最大表示法

    3.最小表示法

    (扩展KMP)

    hdu2594  模板题

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    using namespace std;
    /*
    * 扩展KMP算法
    */
    //nxt[i]:x[i...m-1]与x[0...m-1]的最长公共前缀
    //extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
    int nxt[100050];
    int extend[100050];
    char s[100050], t[100050];
    void pre_EKMP(char x[],int m,int nxt[])
    {
        nxt[0]=m;
        int j=0;
        while(j+1<m && x[j]==x[j+1]) j++;
        nxt[1]=j;
        int k=1;
        for(int i=2;i<m;i++)
        {
            int p=nxt[k]+k-1;
            int L=nxt[i-k];
            if(i+L<p+1)nxt[i]=L;
            else
            {
                j=max(0,p-i+1);
                while(i+j<m && x[i+j]==x[j])j++;
                nxt[i]=j;
                k=i;
            }
        }
    }
    void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
    {
        pre_EKMP(x,m,nxt);
        int j=0;
        while(j<n && j<m && x[j]==y[j]) j++;
        extend[0]=j;
        int k=0;
        for(int i=1;i<n;i++)
        {
            int p=extend[k]+k-1;
            int L=nxt[i-k];
            if(i+L<p+1)
                extend[i]=L;
            else
            {
                j=max(0,p-i+1);
                while(i+j<n && j<m && y[i+j]==x[j]) j++;
                extend[i]=j;
                k=i;
            }
        }
    }
     
    int main()
    {
        while(cin >> s >> t)
        {
            int slen = strlen(s),tlen = strlen(t);
            EKMP(s,slen,t,tlen,nxt,extend);
            int ans = 0;
     
            for(int i = tlen - 1, j = 0; j < slen; j++, i--)
            {
                if(extend[i] == tlen - i)
                {
                    ans = max(ans, extend[i]);
                }
            }
            if(ans)
            {
                for(int i = 0; i < ans; i++)
                    cout << s[i];
                cout << " ";
            }
            cout << ans <<endl;
        }
        return 0;
    }
    View Code

    (最小表示法)

    hdu2609

    题目链接:
    http://acm.hdu.edu.cn/showproblem.php?pid=2609


    思路:
    将每个字符串转换成最小串,然后放在set里面去重。

    最小表示法:

    循环字符串的最小表示法的问题可以这样描述:

    对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。

    由于语言能力有限,还是用实际例子来解释比较容易:

    设S=bcad,且S’是S的循环同构的串。S’可以是bcad或者cadb,adbc,dbca。而且最小表示的S’是adbc。

    对于字符串循环同构的最小表示法,其问题实质是求S串的一个位置,从这个位置开始循环输出S,得到的S’字典序最小。

    维护两个指针i,j。

    令i=0,j=1

    如果S[i] > S[j] i=j, j=i+1

    如果S[i] < S[j] j++

    如果S[i]==S[j] 设指针k,分别从i和j位置向下比较,直到S[i] != S[j]

             如果S[i+k] > S[j+k] i=i+k

             否则j++

    返回i和j的小者

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <set>
    #include <algorithm>
    using namespace std;
     
    const int N = 205;
    int n,len;
    set<string> v;
    char s[N], t[N];
     
    int minRepresstation(char *s){
        int i = 0,j = 1,k = 0;
        while(i<len && j<len && k<len){
            int tmp = s[(i+k)%len]-s[(j+k)%len];
            if(tmp == 0)
                k++;
            else{
                if(tmp > 0)
                    i += k+1;
                else
                    j += k+1;
                if(i == j)
                    j++;
                k = 0;
            }
        }
        return min(i,j);
    }
     
    void getMin(char* str) {
        str[len/2] = '';
        v.insert (str);
    }
     
    int main(){
        while(~scanf("%d", &n)){
            v.clear();
            for(int i = 0; i < n; i++){
                scanf("%s",t);
                strcpy(s,t);
                strcat(s,t);
                len = strlen(s);
                int k = minRepresstation(s);
                getMin(s+k);
            }
            printf("%d
    ",v.size());
        }
        return 0;
    }
    View Code

    hdu3374 (最小表示法 + 最大表示法)

     

    题意:

    给你一个字符串,问这个字符串经过移动后的字典序最小的字符串的首字符位置和字典序最大的字符串的首字符的位置,和能出现多少次最小字典序的字符串和最大字典序的字符串

    思路:
    利用最小表示法与最大表示法O(n)复杂度求出最小字典序和最大字典序串出现位置,然后利用kmp求出next,利用next数组性质求出循环节次数,因为最小和最大字典序串出现次数等于循环节次数

    View Code
  • 相关阅读:
    codevs 3249 搭积木
    BSGS算法+逆元 POJ 2417 Discrete Logging
    POJ 1012 Joseph
    SPFA cojs 176. [USACO Feb07] 奶牛聚会
    素数筛 codevs 1675 大质数 2
    单片机软件proteus的汉化步骤
    直升机和固定翼实操期末考试
    二、万用表使用方法
    拉伸切除
    拔模
  • 原文地址:https://www.cnblogs.com/zyddd915/p/11747820.html
Copyright © 2020-2023  润新知