zoukankan      html  css  js  c++  java
  • 【后缀数组】【poj2774】【 Long Long Message】

    题意:

    求两个串的最长连续子串。


    我的想法:

          枚举第二个串...在第一个串的后缀数组中二分查找.

          复杂度NlogN。最坏情况N^2


    题解:

    (3)height 数组:定义height[i]=suffix(SA[i-1])和suffix(SA[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。

    (4) h[i]=height[rank[i]],也就是suffix(i)和在它前一名的后缀的最长公共前缀。

    (5)LCP(i,j):对正整数i,j 定义LCP(i,j)=lcp(Suffix(SA[i]),Suffix(SA[j]),其中i,j 均为1 至n 的整数。LCP(i,j)也就是后缀数组中第i 个和第j 个后缀的最长公共前缀的长度。其中,函数lcp(u,v)=max{i|u=v},也就是从头开始顺次比较u 和v 的对应字符,对应字符持续相等的最大位置,称为这两个字符串的最长公共前缀。

    2.2   几个性质

    (1)LCP(i,j)=min{height[k]|i+1≤k≤j},也就是说,计算LCP(i,j)等同于询问一维数组height 中下标在i+1 到j 范围内的所有元素的最小值。

       

    (1) 最长公共子串。给定两个字符串A 和B,求最长公共子串。

    『解析』先将第二个字符串写在第一个字符串后面,中间用一个没有出现过的字符隔开,再求这个新的字符串的后缀数组。当suffix(sa[i-1]) 和suffix(sa[i])不是同一个字符串中的两个后缀时,max{height[i]}才是满足条件


    ..代码 二段 有一种WA了1万次才过
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <string>
    #define oo 0x13131313
    using namespace std;
        /*
        *suffix array
        *倍增算法  O(n*logn)
        *待排序数组长度为n,放在0~n-1中,在最后面补一个0
        *build_sa( ,n+1, );//注意是n+1;
        *getHeight(,n);
        *例如:
        *n   = 8;
        *num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0
        *rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值
        *sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值
        *height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值
        *
        */
    const int MAXN=300000+5;
    char S1[MAXN],S2[MAXN];
    int sa[MAXN];
    int t1[MAXN],t2[MAXN],c[MAXN];
    int rank[MAXN],height[MAXN];
    void build_sa(int s[],int n ,int m)
    {
        int i,j,p,*x=t1,*y=t2;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[i]=s[i]]++;
        for(int i=0;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        for(j=1;j<=n;j<<=1)
        {
            p=0;
            for(i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[y[i]]]++;
            for(i=0;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(i=1;i<n;i++)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;
            if(p>=n) break;
            m=p;
        }
    }
    int s[MAXN];
    int len1,len2,ans=0;
    void getHeight(int s[],int n)
    {
        int i,j,k=0;
        for(i=0;i<=n;i++)rank[sa[i]]=i;
        for(i=0;i<n;i++)
        {
            if(k)k--;
            j=sa[rank[i]-1];
            while(s[i+k]==s[j+k])k++;
            height[rank[i]]=k;
        }
    }
    int main()
    {
       // freopen("a.in","r",stdin);
       // freopen("a.out","w",stdout);
    	while(scanf("%s",S1)!=EOF)
        {
            int ans=0;
            len1=strlen(S1);
            scanf("%s",S2);
            len2=strlen(S2);
            for(int i=0;i<len1;i++) s[i]=S1[i];
            s[len1]='$';
            for(int i=len1+1;i<=len2+len1+1;i++) s[i]=S2[i-len1-1];
            build_sa(s,len1+len2+2,256);
            getHeight(s,len1+len2+1);
            for(int i=2;i<=len1+len2+1;i++)
            {
                int MAX=max(sa[i-1],sa[i]);
                int MIN=min(sa[i-1],sa[i]);
                if(MAX>len1&&MIN<len1)
                {
                    if(ans<height[i])
                        ans=height[i];
                }
            }
            cout<<ans<<endl;
        }
    }
    

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <ctime>
    #include <algorithm>
    #include <iostream>
    #include <sstream>
    #include <string>
    #define oo 0x13131313
    using namespace std;
        /*
        *suffix array
        *倍增算法  O(n*logn)
        *待排序数组长度为n,放在0~n-1中,在最后面补一个0
        *build_sa( ,n+1, );//注意是n+1;
        *getHeight(,n);
        *例如:
        *n   = 8;
        *num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最后一位为0,其他大于0
        *rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };rank[0~n-1]为有效值,rank[n]必定为0无效值
        *sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]为有效值,sa[0]必定为n是无效值
        *height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]为有效值
        *
        */
    const int MAXN=300000+5;
    char S1[MAXN],S2[MAXN];
    int sa[MAXN];
    int t1[MAXN],t2[MAXN],c[MAXN];
    int rank[MAXN],height[MAXN];
    void build_sa(int s[],int n ,int m)
    {
        int i,j,p,*x=t1,*y=t2;
        for(int i=0;i<m;i++) c[i]=0;
        for(int i=0;i<n;i++) c[x[i]=s[i]]++;
        for(int i=0;i<m;i++) c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
        for(j=1;j<=n;j<<=1)
        {
            p=0;
            for(i=n-j;i<n;i++) y[p++]=i;
            for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[y[i]]]++;
            for(i=0;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);
            p=1;x[sa[0]]=0;
            for(i=1;i<n;i++)
                x[sa[i]]=(y[sa[i-1]]==y[sa[i]])&&(y[sa[i-1]+j]==y[sa[i]+j])?p-1:p++;
            if(p>=n) break;
            m=p;
        }
    }
    int s[MAXN];
    int len1,len2,ans=0;
    void getHeight(int s[],int n)
    {
        int i,j,k=0;
        for(i=0;i<=n;i++)rank[sa[i]]=i;
        for(i=0;i<n;i++)
        {
            if(k)k--;
            j=sa[rank[i]-1];
            while(s[i+k]==s[j+k])k++;
            height[rank[i]]=k;
        }
    }
    int main()
    {
        //freopen("a.in","r",stdin);
        //freopen("a.out","w",stdout);
    	while(scanf("%s",S1)!=EOF)
        {
            int ans=0;
            len1=strlen(S1);
            scanf("%s",S2);
            len2=strlen(S2);
            for(int i=0;i<len1;i++) s[i]=S1[i];
            s[len1]='@';
            for(int i=len1+1;i<=len2+len1+1;i++) s[i]=S2[i-len1-1];
            build_sa(s,len1+len2+2,128);
            getHeight(s,len1+len2+1);
            for(int i=2;i<=len1+len2+1;i++)
            {
                if((long long)(sa[i]-len1)*(long long)(sa[i-1]-len1)<0)     //乘爆了long long WA了无数发 真是酸爽
                {
                    if(ans<height[i])
                        ans=height[i];
                }
            }
            cout<<ans<<endl;
        }
    }
    



  • 相关阅读:
    WPF自定义RoutedEvent事件代码段
    微信聊天和通讯录按钮样式
    【转】c#、wpf 字符串,color,brush之间的转换
    模块式开发
    通过属性进行浅拷贝
    【转】string.Format对C#字符串格式化
    酷学习笔记——前言
    C# 连蒙带骗不知所以然的搞定USB下位机读写
    C# Ioc、DI、Unity、TDD的一点想法和实践
    虹软人脸识别速度测试征集
  • 原文地址:https://www.cnblogs.com/zy691357966/p/5480325.html
Copyright © 2011-2022 走看看