演算法學習 字尾陣列(SA)

2022-07-24 12:03:11 字數 2289 閱讀 4726

【參考部落格】

【定義】

【字尾】從第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是之前提到的,每次列舉的字串長度

【模板題】

【luogu p3809】

求乙個字串的sa

#include#include

#include

#include

using

namespace

std;

const

int maxn = 1000010

;char

s[maxn];

intsa[maxn];

intx[maxn], c[maxn], y[maxn];

void get_sa(char *s)

return;}

intmain()

view code

【擴充套件】

lcp/height陣列的求取

演算法學習 字尾陣列

乙個字串的題,有姿勢水平的oiers的腦中應該要浮現出許多演算法 但是我沒有姿勢,也沒有水平,除了kmp和trie樹,什麼也想不起來。直到我學了它 字尾陣列!多虧這玩意兒,我現在什麼都想不起來了。字尾陣列幹嘛用的?主要處理同乙個字串中的重複子串問題。如何實現?注意到每乙個子串,都是乙個字尾的某個字首...

SA 字尾陣列 學習筆記

今天沒事幹,學了sa 其實是模擬賽掛了 引用資料 2009年國家集訓隊 洛谷 273期 我們記 sa i 為排名為 i 的字尾的開始位置。rk i 為開始位置為 i 的字尾的排名。我們採用基數排序,因為這樣在排序第一關鍵字的時候,第二關鍵字順序相對正確。舉例子就是21和12排序,因為你的程式不知道什...

字尾陣列(SA)學習記錄

乙隻只會字尾自動機卻不會字尾陣列的弱雞做了一下hdu 1403,結果sam被卡記憶體了,然後學習了一下sa。以下兩道題都是求lcs,區別在於字串長度。hdu 1403 1 include 2 include 3 include 4 include 5 define rank rank 6using ...