字尾陣列(suffix array)

2021-09-28 13:58:00 字數 3564 閱讀 8591

最近系統地學習了一下sa,就演算法本身並不是十分複雜,但關係到字尾陣列的題型卻很多,於是打算整理一下。

計算字串sa通常有倍增和dc3兩種做法,一般選擇倍增,因為常數小且寫起來方便一些。

1. 不可重疊最長重複子串(poj1743)

分析:題目並不是裸的不可重疊最長重複子串問題,需要對於問題進行一些修正,考慮相鄰兩位之間的差值,再進行負數修正,就可以轉化到這樣的題型。

在字尾陣列的很多問題中,height陣列具有很好的性質,由於height陣列是表示,相鄰排名的字尾的最長字首長度,而這道題相當於求一對相同的字首,不過對於字首有不相交的性質。

首先我們二分答案k

kk,如果有一段連續字尾的height都大於k

kk,說明這些字尾具有相同的字首且長度大於k

kk,那麼我們只需要這些字尾中sasa

sa差值大於k,顯然有兩個長度大於k

kk的子串。

(因為如果兩個位置的sa差值大於k

kk,說明他們之間相隔距離大於k

kk,自然字首不會重疊)

//#include 

//#include

//#include

//#include

//#include

//#include

//#include

#include

#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )

#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )

#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )

using

namespace std;

int_read()

const

int maxn =

22222

;int wa[maxn]

, wb[maxn]

, wv[maxn]

, _sum[maxn]

;int

cmp(

int*r ,

int a ,

int b ,

int l )

voidda(

int*r ,

int*sa ,

int n ,

int m )

return;}

int rank[maxn]

, height[maxn]

;void

calch

(int

*r ,

int*sa ,

int n )

return;}

bool

check

(int n ,

int*sa ,

int k )

else

}return0;

}int r[maxn]

, sa[maxn]

;int

main()

r[n]=0

;da( r , sa , n +1,

200)

;calch

( r , sa , n )

;int l =

1, r = n;

while

( l <= r )

if( r >=

4) cout << r +

1<< endl;

else cout <<

0<< endl;

}return0;

}

此題作為sa的模板題

2. 可重疊的k次最長重複子串(poj3261)

分析:這個和上面一題做法相似,同樣是二分答案ans,每次判斷是否存在k個連續字尾滿足height值不小於ans。

3. 不相同的子串的個數(spoj694)

分析:對於任意子串來講,其都可以看做某個字尾的字首,那麼我們需要統計所有不同字首的個數,對於字尾suf

fix(

sa[i

])

suffix(sa[i])

suffix

(sa[

i])來講,對於全部的貢獻為n−s

a[i]

+1

n-sa[i]+1

n−sa[i

]+1,同時需要去掉與sa[

i−1]

sa[i - 1]

sa[i−1

]有交集的hei

ght[

i]

height[i]

height

[i]個字首,所以直接統計出答案為n∗(

n+1)

/2−σ

(hei

ght[

i]

)n*(n+1)/2-\sigma(height[i])

n∗(n+1

)/2−

σ(he

ight

[i])

.

//#include 

//#include

//#include

//#include

//#include

//#include

//#include

#include

#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )

#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )

#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )

using

namespace std;

int_read()

const

int maxn =

55000

;int wa[maxn]

, wb[maxn]

, wv[maxn]

, _sum[maxn]

;int

cmp(

int*r ,

int a ,

int b ,

int l )

voidda(

int*r ,

int*sa ,

int n ,

int m )

return;}

int rk[maxn]

, height[maxn]

;void

calch

(int

*r ,

int*sa ,

int n )

return;}

int r[maxn]

, sa[maxn]

;typedef

long

long ll;

intmain()

cout << ans << endl;

}return0;

}

以上是關於單個字串有關sa的一些典型例題,下面會做一些多字串的問題。

Suffix Array 字尾陣列

顧名思義,suffixarray 以下有時簡稱sa 和字串的字尾有關。字尾 字串中某個位置一直到結尾的子串。sa中討論包括了原串和空串 所以共有len 1個字尾。字尾陣列 字串的所有字尾組成的按字典序從小到大排好的陣列。由於sa中記錄的都是字串的字尾,所以sa只需要記錄其表示的字尾的起始位置。由於比...

字尾陣列(Suffix Array)

字尾陣列是處理字串的有力工具。sa儲存乙個字串按字典序排列的字尾,如圖 rank陣列儲存字尾i的名次,就是把sa反過來,上圖中 rank 1 2,rank 2 8 height陣列儲存相鄰兩個sa字尾之間公共字首的長度,如圖 思路 用倍增的方法對每個字元開始的長度為2 k2 k 2k子字串進行排序,...

字尾陣列suffix array

倍增演算法,時間複雜度o nlogn sa從小到大儲存相對大小的下標 理解lsd,x陣列,sa陣列 char s maxn int sa maxn t maxn t2 maxn c maxn n void build sa int m void build sa int m int cmp suff...