zoukankan      html  css  js  c++  java
  • AcWing 140. 后缀数组(hash+二分)

    题目大意:给一个字符串,假设长度为n,那么它就有n个后缀,求排名为i的字典序,并求出排序中相邻串的最长公共前缀。

    题解:hash+二分(假设字符串从1开始)

    如果将n个后缀字符串用sort排序,需要比较nlogn次,每次比较最差需要O(n),所以时间复杂度为O(n^2logn)

    考虑将O(n)的比较用二分优化为log(n)。

    当比较两个字符串时,我们只需要比较它的第一个不相同的位置,所以我们二分最长公共前缀,设为maxlen。

    若str1[maxlen+1]>str2[maxlen+1].则str1的字典序更大。

    用前缀哈希值判断前缀是否相等。 

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    typedef unsigned long long ull; 
    const int N=300000+3;
    const ull base=131;
    
    int len;
    char s[N];
    int sa[N];
    ull f[N],p[N];
    
    ull get_hash(int l,int r)
    {
        return f[r]-f[l-1]*p[r-l+1];
    }
    
    bool check(int x,int a,int b)
    {
        if(get_hash(a,a+x-1)==get_hash(b,b+x-1)) return true;
        else return false;
    }
    
    int get_max_pre(int x,int y)
    {
        int l,r,mid,ans;
        l=0;r=min(len-x+1,len-y+1);
        while(l<=r)
        {
            mid=(l+r)>>1;
            if(check(mid,x,y)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        return ans;
    }
    
    bool cmp(int x,int y)
    {
        int max_l=get_max_pre(x,y);
        int xv=s[max_l+x];
        int yv=s[max_l+y];
        return xv<yv;
    }
    
    int main()
    {
        scanf("%s",s+1);
        len=strlen(s+1);
        p[0]=1;
        for(int i=1;i<=len;i++)
        {
            p[i]=p[i-1]*base;
            f[i]=f[i-1]*base+(s[i]-'a'+1);
            sa[i]=i;
        }
        sort(sa+1,sa+len+1,cmp);
        for(int i=1;i<=len;i++) printf("%d ",sa[i]-1);
        printf("
    ");
        for(int i=1;i<=len;i++) printf("%d ",get_max_pre(sa[i],sa[i-1]));
        return 0;
    }
  • 相关阅读:
    Redis数据类型及操作详解
    【Linux】——搭建redis
    【Linux】——搭建nexus
    更多体会,更多收获!(2015年终总结)
    【WebService】——入门实例
    HashSet如何判定两个元素相同
    WEB-INF目录
    Java基础——集合
    从零开始配置Jenkins(三)——用户权限管理
    Activiti工作流(三)——流程变量
  • 原文地址:https://www.cnblogs.com/zzyh/p/14785896.html
Copyright © 2011-2022 走看看