zoukankan      html  css  js  c++  java
  • 后缀数组学习笔记

    【吐槽】学了好久的后缀数组,看了各个大神博客,还是没懂= =,看起来好难的一个东西【一堆堆for】。主要还是自己码代码的能力太弱了。。。。

    后缀数组,顾名思义,一定与后缀有关。后缀数组简称sa,sa[i]表示在字符串s的所有后缀中,排名第i的后缀的首字母在字符串中的位置。【排名从0开始】
    比如,对于字符串"ababa",排名第一的后缀是最后一个a,那么sa[0]=4.

    我们要做的事情,就是求出这个数组,怎么求呢?
    观察下面这张图片
    就像一个两位数的比较
    利用倍增的思想,我们先按每个后缀的第一个字符排序,再按每个后缀的前2个字符排序,再按每个后缀的前4个字符排序......直到没有相同排名为止
    具体排序如何实现?
    利用之前的排序,4个字符的排序其实可以转化为两个2个字符的排序,任意一次排序都是一个双关键字排序。
    我们就可以利用基数排序很快的进行排序。

    什么是基数排序?
    基数排序遵循这样一个事实:按关键字对排序结果的的决定性从弱到强进行排序,最后的结果一定符合排序要求。
    然后我们拿一个桶,装下出现的每一种数,然后再利用桶的前缀和来求出每个位的排序
    举个例子:
    3 4 6 82 99
    我们知道,数字排序可以看作多个关键字排序:个位、十位、百位、千位......其中越高位决定性越强。
    于是我们从个位开始排序【由于每个数都是0~9之间的,所以我们只需要十个桶】:
    每个桶表示这个数字有多少个,到最后结果应该是这样的:
        0 0 1 1 1 0 1 0 0 1
     [  0 1 2 3 4 5 6 7 8 9  ]
    然后我们求出前缀和,表示不大于这个数的数有多少个
    0 0 1 2 3 3 4 4 4 5
    利用前缀和,我们就能很快得到排序


    利用基数排序,我们就可以实现后缀数组啦:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=100005;
    
    char s[maxn];
    
    int sa[maxn],t1[maxn],t2[maxn],buc[maxn],m='z'+1,n;
    
    void solve(){
    	int *x=t1,*y=t2;
    	n=strlen(s);
    	for(int i=0;i<m;i++) buc[i]=0;
    	for(int i=0;i<n;i++) buc[x[i]=s[i]]++;
    	for(int i=1;i<m;i++) buc[i]+=buc[i-1];
    	for(int i=n-1;i>=0;i--) sa[--buc[x[i]]]=i;
    	
    	for(int k=1;k<=n;k<<=1){
    		int p=0;
    		//排序第二关键字
    		for(int i=n-k;i<n;i++) y[p++]=i;
    		for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
    		//排序第一关键字
    		for(int i=0;i<m;i++) buc[i]=0;
    		for(int i=0;i<n;i++) buc[x[y[i]]]++;
    		for(int i=1;i<m;i++) buc[i]+=buc[i-1];
    		for(int i=n-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i];
    		//求出各个后缀当前的的排名
    		swap(x,y);
    		p=1;x[sa[0]]=0;
    		for(int i=1;i<n;i++)
    			x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k] ? p-1:p++;
    		//排名各不相同,排序完成,直接退出
    		if(p>=n) break;
    		m=p;
    	}
    }
    
    int main(){
    	cin>>s;
    	solve();
    	for(int i=0;i<n;i++) printf("%d ",sa[i]+1);
    	cout<<endl;
    	return 0;
    }
    



    2017.9.23添加

    题解
    拆环成链,求后缀排序,然后按排名顺序将前一个字符输出即可
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    using namespace std;
    const int maxn=1000005,maxm=1000000,INF=2000000000,P=1000000007;
    
    inline int read(){
    	int out=0,flag=1;char c=getchar();
    	while(c<48||c>57) {if(c=='-') flag=-1;c=getchar();}
    	while(c>=48&&c<=57){out=out*10+c-48;c=getchar();}
    	return out*flag;
    }
    
    char s[maxn];
    int buc[maxm],t1[maxn],t2[maxn],sa[maxn],m=0,n,N;
    
    void init(){
    	scanf("%s",s);
    	N=strlen(s);
    	char t='';
    	for(int i=0;i<N;i++){
    		s[N+i]=s[i];
    		t=max(t,s[i]);
    	}
    	m=t+1;
    	n=2*N;
    }
    
    void solve(){
    	int *x=t1,*y=t2;
    	for(int i=0;i<m;i++) buc[i]=0;
    	for(int i=0;i<n;i++) buc[x[i]=s[i]]++;
    	for(int i=1;i<m;i++) buc[i]+=buc[i-1];
    	for(int i=n-1;i>=0;i--) sa[--buc[x[i]]]=i;
    	
    	for(int k=1;k<=n;k<<=1){
    		int p=0;
    		
    		for(int i=n-k;i<n;i++) y[p++]=i;
    		for(int i=0;i<n;i++) if(sa[i]>=k){
    			y[p++]=sa[i]-k;
    		}
    		
    		for(int i=0;i<m;i++) buc[i]=0;
    		for(int i=0;i<n;i++) buc[x[y[i]]]++;
    		for(int i=1;i<m;i++) buc[i]+=buc[i-1];
    		for(int i=n-1;i>=0;i--) sa[--buc[x[y[i]]]]=y[i];
    		swap(x,y);
    		p=1;x[sa[0]]=0;
    		for(int i=1;i<n;i++)
    			x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k] ? p-1:p++;
    		if(p>=n) return;
    		m=p;
    	}
    }
    
    void print(){
    	for(int i=0;i<n;i++){
    		if(sa[i]<N){
    			printf("%c",s[sa[i]+N-1]);
    		}
    	}
    	printf("
    ");
    }
    
    int main(){
    	init();
    	solve();
    	print();
    	return 0;
    }
    


  • 相关阅读:
    python 中关于kafka的API
    python 中对json的操作
    python 错误--UnboundLocalError: local variable '**' referenced before assignment
    storm问题记录(1) python 不断向kafka中写消息,spout做为消费者从kafka中读消息并emit给bolt,但是部分消息没有得到bolt的处理
    nodejs+kafka+storm+hbase 开发
    python构造数据
    Head first java中提到的学习方法,很受用
    【机器学习 第2章 学习笔记】模型评估与选择
    路书
    二分搜索
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282898.html
Copyright © 2011-2022 走看看