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

    描述

    后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围。在本题中,我们希望使用快排、Hash与二分实现一个简单的 O(n log^2⁡n ) 的后缀数组求法。详细地说,给定一个长度为 n 的字符串S(下标 0~n-1),我们可以用整数 k(0≤k<n) 表示字符串S的后缀 S(k~n-1)。把字符串S的所有后缀按照字典序排列,排名为 i 的后缀记为 SA[i]。额外地,我们考虑排名为 i 的后缀与排名为 i-1 的后缀,把二者的最长公共前缀的长度记为 Height[i]。我们的任务就是求出SA与Height这两个数组。<n) i="" i-1="" p="">

    输入格式

    一个字符串,长度不超过30万。

    输出格式

    第一行为数组SA,相邻两个整数用1个空格隔开。

    第二行为数组Height,相邻两个整数用1个空格隔开,特别地,假设Height[1]=0。

    样例输入

    ponoiiipoi

    样例输出

    9 4 5 6 2 8 3 1 7 0
    0 1 2 1 0 0 2 1 0 2

    样例解释

    排名第一(最小)的后缀是9(S[9~9],即字符串 i),第二的是后缀4(S[4~9],即字符串iiipoi),第三的是后缀5(S[5~9],即字符串iipoi)以此类推。Height[2]表示排名第2与第1的后缀的最长公共前缀,长度为1,Height[3]表示排名第3与第2的后缀的最长公共前缀,长度为2,以此类推。

    思路:因为要按照字典序排序,既然排序,那么就想到了快排sort。

    那就要自定义比较函数,如果对于两个字符串O(n)扫描比较,那么总体复杂度O(n2logn)

    我们可以二分比较的长度,对于同样长的字符串通过对字符串hash得到的hash值比较其是否相同,O(logn)找出其不同位置,然后比较该位置大小,这样复杂度O(nlog2n)

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1000005;
    unsigned long long f[maxn],p[maxn];
    char word[maxn];
    int n;
    struct Node
    {
        int pos;
        int hei;
        Node(int x = 0,int h=0):pos(x),hei(h) {}
    } node[maxn];
    
    unsigned long long getf(int l,int r)
    {
        return f[r] - f[l-1]*p[r-l+1];
    }
    
    int cal(Node a,Node b)
    {
        int lena = n - a.pos + 1;
        int lenb = n - b.pos + 1;
        int l = 1,r = min(lena,lenb);
        while(l <= r)
        {
            int mid = (l+r)>>1;
            if(getf(a.pos,a.pos+mid-1) == getf(b.pos,b.pos+mid-1))
            {
                l = mid + 1;
            }
            else
            {
                r = mid - 1;
            }
        }
        return l-1;
    }
    bool cmp(Node a,Node b)
    {
        int t = cal(a,b);
        return  word[a.pos+t] < word[b.pos+t];
    }
    int main()
    {
        scanf("%s",word+1);
        n = strlen(word+1);
        p[0] = 1;
        f[0] = 0;
        for(int i=1; i<=n; i++)
        {
            node[i].pos = i;
            f[i] = f[i-1] * 131 + word[i] - 'a' + 1;
            p[i] = p[i-1]*131;
        }
        sort(node+1,node+1+n,cmp);
        for(int i=2; i<=n; i++)
        {
            node[i].hei = cal(node[i-1],node[i]);
        }
        for(int i=1; i<=n; i++)
        {
            printf("%d",node[i].pos-1);
            if(i != n)
                printf(" ");
            else
                printf("
    ");
        }
        for(int i=1; i<=n; i++)
        {
            printf("%d",node[i].hei);
            if(i != n)
                printf(" ");
            else
                printf("
    ");
        }
    }
    View Code
  • 相关阅读:
    Linux:grep 命令
    Linux:sort
    Java中路径相关的获取方式
    Spring boot 配置 Tomcat 临时文件缓存目录
    zabbix :web 界面显示的监控项值为0或者空
    Maven:禁止编码指定类型的资源文件
    Maven:element '******' cannot have character [children]
    MySQL:数据库名或者数据表名包含-
    Linux:sed
    Lucene 6.0下使用IK分词器
  • 原文地址:https://www.cnblogs.com/iwannabe/p/10653581.html
Copyright © 2011-2022 走看看