• 后缀排序


    Tim正在自学《数据结构》,他刚刚学会如何比较两个字符串大小。书上是这么说的(和Pascal语言中的比较规则相同,学习过Pascal语言的同学可以跳过这段): 

    比较两个不同字符串s1=’p1p2p3…pN’和s2=’q1q2q3…qM’的大小,设N<=M。
    若s1是s2的前缀,则s1qi,且i最小;若pis2。
    Tim想通过练习熟练运用这个规则,于是打算出许多字符串,并将它们从小到大排序。可是Tim非常懒,随机写出 K个很长的字符串实在是太麻烦了。不过聪明的他想到了一个好办法,他写了一个很长的字符串,自言自语说,“我只要把这个字符串的所有后缀从小到大排序就可以了”。
    Input
    仅有一行,且是一个仅包含小写字母的字符串,长度K不超过10^5。
    Output
    有K行,每行一个数字,第i行的数字Pi表示所有后缀中,第i小的是由原字符串第Pi个字符引导的后缀。
    Sample Input
    mississippi
    Sample Output
    11
    8
    5
    2
    1
    10
    9
    7
    4
    6
    3

    Sol:

    sa[i]=j...排名第i的后缀是从原串中的第j个位置开始的

    rank[i]=j...原串中第i个位置开始的后缀,排名为j

    两者是个互逆的函数,整个程序就是两个数组倒来倒过

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #define maxn 210000
    #define ll long long
    #define fill(a,b) memset(a,b,sizeof(a))
    using namespace std;
    int Rank[maxn],sa[maxn],a[maxn],wr[maxn],rsort[maxn],y[maxn];
    char c[110000];
    inline bool cmp(int k1,int k2,int ln)
    {
    return wr[k1]==wr[k2]&&wr[k1+ln]==wr[k2+ln];
    }
    inline void get_sa(int n,int m)
    {
        int k,p,ln;
        memcpy(Rank,a,sizeof(Rank));  //将a数组copy给Rank 
        memset(rsort,0,sizeof(rsort));
        for(int i=1;i<=n;i++) //对于每个字符统计它的出现次数 
    	     rsort[Rank[i]]++;
        for(int i=1;i<=m;i++) //对于每个字符统计有多少个比它小 
    	    rsort[i]+=rsort[i-1];
        for(int i=n;i>=1;i--) 
    	     sa[rsort[Rank[i]]--]=i;
    	     //sa[i]=j,排在第i小的后缀串是从原字符串第j个位置开始的 
        ln=1; p=0;
        while (p<n)
        {
            k=0;
            for(int i=n-ln+1;i<=n;i++) 
    		     y[++k]=i;
            for(int i=1;i<=n;i++) 
    		    if(sa[i]>ln) y[++k]=sa[i]-ln;
            for(int i=1;i<=n;i++) 
    		     wr[i]=Rank[y[i]];
    		//rank[i]=j ,从i开始的后缀是第 j 名的(和 sa 互逆,是排名(值))
            memset(rsort,0,sizeof(rsort));
            for(int i=1;i<=n;i++) 
    		     rsort[wr[i]]++;
            for(int i=1;i<=m;i++) 
    		    rsort[i]+=rsort[i-1];
            for(int i=n;i>=1;i--) 
    		     sa[rsort[wr[i]]--]=y[i];
            for(int i=1;i<=n;i++) 
    		    wr[i]=Rank[i];
            p=1; 
    		Rank[sa[1]]=1;
            for(int i=2;i<=n;i++) 
            {
                if(!cmp(sa[i],sa[i-1],ln)) p++;
                Rank[sa[i]]=p;
            }
            m=p; 
    		ln*=2;
        }
        for(int i=1;i<=n;i++)
            printf("%d
    ",sa[i]);
    }
    int main(){
        scanf("%s",c+1);
        int n=strlen(c+1);
        for(int i=1;i<=n;i++) 
    	     a[i]=c[i];
        get_sa(n,300);
        return 0;
    }
    

      

  • 相关阅读:
    你有没有发现你的文章被人侵权?推荐一个工具给你
    带你找到五一最省的旅游路线【dijkstra算法代码实现】
    【最短路径Floyd算法详解推导过程】看完这篇,你还能不懂Floyd算法?还不会?
    Floyd算法java实现demo
    【销售系统设计01】关于线上与线下销售业绩冲突处理
    jenkins maven 自动远程发布到服务器,钉钉提醒团队
    研究windows下SVN备份及还原恢复方案
    xamarin.android SurfaceView 实现 游戏 触摸摇杆
    C++ 头文件和源文件 和 编译流程
    十大经典排序算法总结(JavaScript描述)
  • 原文地址:https://www.cnblogs.com/cutemush/p/12331639.html
Copyright © 2020-2023  润新知