• 字符串专题:KMP POJ 3561


    http://poj.org/problem?id=3461

    KMP这里讲的不错next的求法值得借鉴 http://blog.sina.com.cn/s/blog_70bab9230101g0qv.html

    这道题要用到KMP,基于邝斌牌模板,复杂度O(M+N)

    一开始T了,用了后缀数组,复杂度O(Nlog2n)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<string>
    #include<algorithm>
    using namespace std;
    #define N 100010
    char s[N * 10], p[N];
    /*
    * next[]的含义:x[i-next[i]...i-1]=x[0...next[i]-1]
    * next[i]为满足x[i-z...i-1]=x[0...z-1]的最大z值(就是x的自身匹配)
    */
    void kmp_pre(char x[],int m,int next[])
    {
        int i,j;
        j=next[0]=-1;
        i=0;
        while(i<m)
        {
            while(-1!=j && x[i]!=x[j])j=next[j];
            next[++i]=++j;
        }
    }
    /*
    * kmpNext[]的意思:next'[i]=next[next[...[next[i]]]] (直到next'[i]<0或者x[next'[i]]!=x[i])
    * 这样的预处理可以快一些
    */
    /*void preKMP(char x[],int m,int kmpNext[])
    {
        int i,j;
        j=kmpNext[0]=-1;
        i=0;
        while(i<m)
        {
            while(-1!=j && x[i]!=x[j])j=kmpNext[j];
            if(x[++i]==x[++j])kmpNext[i]=kmpNext[j];
            else kmpNext[i]=j;
        }
    }*/
    /*
    * 返回x在y中出现的次数,可以重叠
    */
    int next[10010];
    int KMP_Count(char x[],int m,char y[],int n)
    {
        //x是模式串,y是主串
        int i,j;
        int ans=0;
        //preKMP(x,m,next);
        kmp_pre(x,m,next);
        i=j=0;
        while(i<n)
        {
            while(-1!=j && y[i]!=x[j])j=next[j];
            i++;
            j++;
            if(j>=m)
            {
                ans++;
                j=next[j];
            }
        }
        return ans;
    }
    int main()
    {
        int ncase;
        int ans;
        scanf("%d", &ncase);
        while(ncase--)
        {
            scanf("%s%s", p, s);
            int lens = strlen(s);
            int lenp = strlen(p);
            ans=KMP_Count(p,lenp,s,lens);
            printf("%d
    ", ans);
        }
        return 0;
    }
    #include<iostream>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,k,m,number;
    int rank[1000005],tmp[1000005],sa[1000005];
    bool common_sa(int i,int j)
    {
        if(rank[i]!=rank[j]) return rank[i]<rank[j];
        else
        {
            int ri=i+k<=n?rank[i+k]:-1;
            int rj=j+k<=n?rank[i+k]:-1;
            return ri<rj;
        }
    }
    void construct_sa(string s,int *sa)
    {
        n=s.length();
        for(int i=0;i<=n;i++)
        {
            sa[i]=i;
            rank[i]=i<n?s[i]:-1;
        }
        for(k=1;k<=m;k*=2) //这里的k是递归到长度为k的串
        {
            sort(sa,sa+n+1,common_sa);
            tmp[sa[0]]=0;
            for(int i=1;i<=n;i++)
            {
                tmp[sa[i]]=tmp[sa[i-1]]+(common_sa(sa[i-1],sa[i])?1:0);
            }
            for(int i=0;i<=n;i++)
            {
                rank[i]=tmp[i];
            }
        }
    }
    bool contain(string s,int *sa,string t)
    {
        int a=0,b=s.length();
        while(b-a>1)
        {
            int c=(a+b)/2;
            if(s.compare(sa[c],t.length(),t)<0) a=c;
            else b=c;
        }
        return s.compare(sa[b],t.length(),t)==0;
    }
    
    int main()
    {
        string mode,donser;
        ios::sync_with_stdio(false);
        cin.tie(NULL);
        cin>>n;
        while(cin>>mode>>donser)
        {
            n=donser.size();
            m=mode.size();
            construct_sa(donser,sa);
            if(!contain(donser,sa,mode)) cout<<"0"<<endl;
            else
            {
                char c=mode[0];
                for(int i=0;i<n;i++)
                {
                    if(donser[i]==c)
                    {
                        int y=rank[i];number=0;
                        for(int j=i;j<n;j++)
                        {
                            if(rank[j]==y) number++;
                        }
                        break;
                    }
                }
                cout<<number<<endl;
            }
        }
        return 0;
    }
    T掉的 后缀数组

     后缀数组这里也有值得说的

    rank数组对字串长度做1 2 4 8这样的增长式划分,划分的最大长度可以直接定为匹配串的长度,

    这样根据rank数组的值和位置就能知道相同的串个数了。

  • 相关阅读:
    优化cocos2d/x程序的内存使用和程序大小
    cocos2d-x移植:xcode到eclipse
    程序员在编程工作中痛苦的压抑着自己某些强烈的情绪
    C++语言的一些问题
    基数排序-图非常清晰明了
    【Cocos2d-X(1.x 2.x) 修复篇】iOS6 中 libcurl.a 无法通过armv7s编译以及iOS6中无法正常游戏横屏的解决方法
    《C++ Primer》笔记-inline内联函数
    走出你的舒适区
    UDP广播与多播
    测试问题反馈需要包含内容总结
  • 原文地址:https://www.cnblogs.com/dzzy/p/5489008.html
Copyright © 2020-2023  润新知