日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

并不对劲的后缀数组

發布時間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 并不对劲的后缀数组 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?

后綴數組sa(x)表示排序后第x位在排序前的位置。

這個東西的求法有兩種,一種是倍增,時間復雜度o(n log n)或o(n log2n),另一種是用不知道什么方法做到的o(n)。

至于第二種方法是什么,并不對勁的人并不知道,所以只說倍增。

考慮正常地比較兩個字符串,都是從頭比較到尾:

?

那么,如果把兩個字符串都斷成兩半,并且已知每一段的排名,就相當于以第一段為第一關鍵字,第二段為第二關鍵字排序了。

根據這個性質,就能想到如果先把字符串的每個位置開始長度為一的子串進行排序后,就能在至多n log n的時間內將每個位置開始長度為二的子串排序。

↑大概長這樣,注意最后要補一個空字符。

以此類推,就能這樣倍增地求出后綴的排序了,還是要注意最后補空字符。

如果用基數排序,每次排序的時間復雜度是o(n)的,那么總復雜度就是o(n log n)了。

如果用快速排序,總復雜度就是o(n log2n),心中有黨常數極小才能過。

#include<algorithm> #include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iomanip> #include<iostream> #include<map> #include<queue> #include<stack> #include<vector> #define rep(i,x,y) for(register int i=(x);i<=(y);++i) #define dwn(i,x,y) for(register int i=(x);i>=(y);--i) #define re register #define maxn 2000010 using namespace std; inline int read() {int xx=0,ff=1;char ch=getchar();while(isdigit(ch)==0&&ch!='-')ch=getchar();if(ch=='-')ff=-1,ch=getchar();while(isdigit(ch))xx=xx*10+ch-'0',ch=getchar();return xx*ff; } void write(int x) {int ff=0;char ch[15];if(x<0){x=-x;putchar('-');}while(x)ch[++ff]=(x%10)+'0',x/=10;if(ff==0)putchar('0');while(ff)putchar(ch[ff--]);putchar(' '); } int sa[maxn],ord[maxn],rnk[maxn],n,m; int sum[maxn]; char s[maxn]; int main() {scanf("%s",s+1);n=strlen(s+1);m=130;rep(i,1,n)sum[rnk[i]=s[i]]++;rep(i,1,m)sum[i]+=sum[i-1];dwn(i,n,1)sa[sum[rnk[i]]--]=i;for (int k=1;k<=n;k<<=1) { //從這里開始到分界線是更新sa的部分 int p=0;rep(i,n-k+1,n)ord[++p]=i;rep(i,1,n)if(sa[i]>=k+1)ord[++p]=sa[i]-k;//ord[i]表示按第二關鍵字排名后排在第i位的在原串中的位置//需要注意的是,原串中的第n-k+1到n位置上的后綴由于加上k后的位置在超過n的地方,需要補空字符//這里假設空字符是最小的,所以按第二關鍵字排序后,第n-k+1到n位置上的后綴排在最前面 rep(i,0,m)sum[i]=0;rep(i,1,n)sum[rnk[i]]++;//計算不同的排名出現了多少次 rep(i,1,m)sum[i]+=sum[i-1];//算前綴和。c[i]表示排名為i的串最后一次出現在排序后的第幾名(當k<n時可能在s中有很多個排名相同的) dwn(i,n,1)sa[sum[rnk[ord[i]]]--]=ord[i];//rnk[ord[i]]表示排序后第i個的排名(可能會重)是多少 //不能直接寫sa[sum[rnk[i]]--]=i//交換前,x[i]表示從i開始的后綴在上一輪的排名//——————————分界線————————————//從這里開始是更新x的部分 swap(rnk,ord);p=1,rnk[sa[1]]=1;rep(i,2,n)rnk[sa[i]]=(ord[sa[i-1]]==ord[sa[i]]&&ord[sa[i-1]+k]==ord[sa[i]+k])?p:++p;if(p>=n)break;m=p;}rep(i,1,n)write(sa[i]);return 0; }

  

轉載于:https://www.cnblogs.com/xzyf/p/8244506.html

總結

以上是生活随笔為你收集整理的并不对劲的后缀数组的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。