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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

算法学习:后缀数组(SA)

發布時間:2025/7/14 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:后缀数组(SA) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【參考博客】

https://xminh.github.io/2018/02/27/%E5%90%8E%E7%BC%80%E6%95%B0%E7%BB%84-%E6%9C%80%E8%AF%A6%E7%BB%86(maybe)%E8%AE%B2%E8%A7%A3.html

?

?


?

【定義】

?

【后綴】從第i位到字符串結尾的子串

??


【解決問題】

?

從而解決

...................在字符串中找子串

...................比較子串關系

...................查找不同子串的數目

?

一般來說都是解決

字符串和子串關系的問題

?


?

【算法學習】

?

后綴數組能夠在 nlogn的時間復雜度內求取出以下數組

?

【注意】明白字符串包含字符的范圍?

?

SA [] 儲存,第 i 個數字表示的是字典序第 i 大的后綴是以 SA_i 開始的后綴

即? ?“排第幾的是哪個后綴

rank [] 儲存,從第i位開始的后綴的字典序排名是 i

即? ?“某個后綴排第幾個”?

?

對SA的求取,我們可以看作對所有的后綴進行排序

而這個排序顯然如果直接莽的話肯定T,所以我們需要另外一種方法

?

這里使用基數排序+倍增的方法進行優化

?

將所有的后綴進行排序得到SA,這是我們的目的

?

基數排序,是對兩個關鍵字的元素進行排序從而達到線性復雜度的方法

顯然,在當兩個后綴第一個字符相等的情況下,我們不可避免的去用第二個字符進行比較

這里我們需要注意到一個事情

第 i 個后綴的第二個字符是第 i + 1 的第一個字符

那這和直接莽好像沒有什么區別?

?

?

所以我們就用到了倍增,每次確定后綴的以前 2 ^ k 長度的字符串排序的順序

然后通過這個,就能夠求出 2 ^ ( k + 1 ) 長度的后綴的前綴

通過,第 i 位的和第 i + k 位的,于是就能求出來

?

因為第一個字符有可能一樣,導致有兩個后綴排名相等

所以總排名數和后綴長度不同

所以長度為2時同理

而當所有總排名和后綴長度相同時,這個時候就找到了所有

?

下面是對使用到的各個數組的意義的描述:

c[] 桶,記錄第 i 位的元素有多少個

x[] 后綴 i 的第一關鍵字,所以最開始是等于第 i 位字符

y[] 第二關鍵字排名第 i 的字符串,第一關鍵字的位置

?

【代碼】

?首先求出所需要的幾個數組的初值

//初始化int n = strlen(s+1);int m = 128;//m只需要大于 ascii(‘z')即可//因為第一步并不知道桶的規模for (int i = 1; i <= n; i++)++c[x[i] = s[i]];//計算每一個字符的數量,同樣的放在一起for (int i = 2; i <= m; i++)c[i] += c[i - 1];//求前綴和for (int i = n; i >= 1; i--) SA[c[x[i]]--] = i;//從后往前,這樣就能求出最開始順序

倍增的同時進行排序

for (int k = 1; k <= n; k <<= 1) //k是之前提到的,每次枚舉的字符串長度 {int num = 0;for (int i = n - k + 1; i <= n; i++) y[++num] = i;//先將最后的幾個去掉for (int i = 1; i <= n; i++)if (SA[i] > k)y[++num] = SA[i] - k;//當這個位置的后綴在長度之外時//將這個位置的字符放到第二關鍵字中for (int i = 1; i <= m; i++)c[i] = 0;//清空桶for (int i = 1; i <= n; i++)c[x[i]]++;//放入第一關鍵字//第一關鍵字是已經算好的//第一次是初始化時計算好的//第二次的計算過程在下面for (int i = 2; i <= m; i++)c[i] += c[i - 1];//和初始化一樣的求前綴和for (int i = n; i >= 1; i--)SA[c[x[y[i]]]--] = y[i], y[i] = 0;//在保證第一關鍵字的同時使用第二關鍵字排序//從后往前,第二關鍵字靠后的會被先剔除掉//考慮下數組的操作 swap(x, y);//這里是為了保存上一步得到的y,沒有太多其他意思x[SA[1]] = 1; num = 1;for (int i = 2; i <= n; i++)x[SA[i]] =(y[SA[i]] == y[SA[i - 1]] && y[SA[i] + k] == y[SA[i - 1] + k]) ?//這里注意回憶SA的意義//比較的是和其排名相近的元素,也是最有可能兩個關鍵字都相同的元素//當字符的第二關鍵字,前后都相同時//說明沒有新的元素,所以不加//如果有,則加 ? num : ++num;if (num == n) break;m = num;}

?


?

【模板題】

?

【luogu P3809】

求一個字符串的SA

?

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 1000010; char s[MAXN]; int SA[MAXN]; int x[MAXN], c[MAXN], y[MAXN]; void get_SA(char *s) {//初始化int n = strlen(s + 1);int m = 128;for (int i = 1; i <= n; i++)++c[x[i] = s[i]];//計算每一個字符的數量,同樣的放在一起for (int i = 2; i <= m; i++)c[i] += c[i - 1];//求前綴和for (int i = n; i >= 1; i--)SA[c[x[i]]--] = i;//從后往前,這樣就能求出最開始順序for (int k = 1; k <= n; k <<= 1){int num = 0;for (int i = n - k + 1; i <= n; i++) y[++num] = i;//把最后幾個字符放進去for (int i = 1; i <= n; i++)//按照順序遍歷if (SA[i] > k)//如果長度大于ky[++num] = SA[i] - k;//把第一個放進去for (int i = 1; i <= m; i++)c[i] = 0;for (int i = 1; i <= n; i++)c[x[i]]++;//x[i]是第一關鍵字for (int i = 2; i <= m; i++)c[i] += c[i - 1];//求前綴和for (int i = n; i >= 1; i--)SA[c[x[y[i]]]--] = y[i], y[i] = 0;swap(x, y);x[SA[1]] = 1; num = 1;for (int i = 2; i <= n; i++)x[SA[i]] = (y[SA[i]] == y[SA[i - 1]] && y[SA[i] + k] == y[SA[i - 1] + k]) ? num : ++num;if (num == n) break;m = num;}return; } int main() {scanf("%s", s + 1);get_SA(s);int n = strlen(s + 1);for (int i = 1; i <= n; i++)printf("%d ", SA[i]);return 0; } View Code

?

?


【擴展】

?

LCP/height數組的求取

?

轉載于:https://www.cnblogs.com/rentu/p/11331536.html

總結

以上是生活随笔為你收集整理的算法学习:后缀数组(SA)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 欧美日韩精品在线播放 | 无码人妻精品一区二区蜜桃网站 | aaa一区二区三区 | 日本亚洲色大成网站www久久 | 国产午夜一区二区三区 | 99精品久久精品一区二区 | 久久精品亚洲无码 | 国产美女视频网站 | 国产超碰91| brazzers精品成人一区 | 欧美午夜一区二区三区 | 黑人精品欧美一区二区蜜桃 | 国产日韩欧美91 | 四虎永久在线精品免费一区二区 | 91挑色| 国产精品美女久久久久av爽 | 国产成人啪精品午夜在线观看 | 欧美大片一区二区三区 | 精品成人久久 | 视频在线播 | 性久久久久久久久久久久 | 日韩免费在线观看 | 91久久综合| 欧美日韩亚洲第一 | 干爹你真棒插曲免费 | 国产福利99| 男女在线观看视频 | 国内精品久久久久久久久久 | 国产主播中文字幕 | 一区二区日韩 | 亚洲欧美激情另类 | 邻家有女4完整版电影观看 欧美偷拍另类 | 亚洲第一视频在线播放 | 男男一级淫片免费播放 | 日本视频在线播放 | 国产视频你懂的 | 日皮视频在线观看 | 国产一区二区三区三州 | 一级黄色在线播放 | 欧洲美一区二区三区亚洲 | 天天插天天插 | 空姐吹箫视频大全 | 亚洲1页 | 天堂中文在线观看 | 中文字幕日韩一区二区三区不卡 | 亚洲91视频 | 久艹伊人| 亚洲色婷婷久久精品av蜜桃 | 久久久久成人精品无码 | 亚洲最大免费视频 | 亚洲福利社 | 天天干一干 | 18深夜在线观看免费视频 | 九九色播| 精品国产乱码一区二区三区99 | 亚洲交性网 | 亚洲无码精品国产 | 看av网站 | 欧洲熟妇精品视频 | 精品人妻一区二 | 亚洲青涩网 | 日本九九视频 | 无码av免费毛片一区二区 | 91精品久久久久久久99蜜桃 | 色多多入口 | 麻豆精品一区二区 | 三级色视频 | 久操新在线 | 黄瓜视频在线观看污 | 日韩av综合在线 | 久久女女 | 九九久久网 | 亚洲精品国产成人av在线 | 日韩一级黄色大片 | 欧美黄色成人 | 国产精品欧美综合亚洲 | www.一区二区.com | 公侵犯人妻一区二区三区 | 18av在线视频 | 蜜臀一区二区三区精品免费视频 | 蜜桃视频在线网站 | 国产精品午夜无码专区 | 激情福利 | 一边吃奶一边摸做爽视频 | 久久久久久久国产精品美女 | 国产一级做a爰片在线看免费 | 一区二区三区视频免费在线观看 | 日韩天天操 | 亚洲区自拍 | 精品少妇一区二区三区免费观 | 国产专区欧美专区 | 欧美日日 | 精品在线小视频 | 天堂欧美城网站网址 | 免费的黄色的视频 | 中国毛片网站 | 美女扒开尿口让男人捅爽 | 最全aⅴ番号库网 | 欧美一区二区三区四区五区 |