字尾陣列初探

2022-09-11 02:15:12 字數 1858 閱讀 9877

前言:jsoi2017round2day2t1字尾陣列模板題一點都沒看出來。不然就翻盤了

痛定思痛後決定惡補字串。

字尾陣列

全是**上抄來的。

學了一周,終於搞懂一些了。

1.基本定義

字串s;

字尾:從位置i開始到結尾的子串,記作suffix(i)=s[i..len[s]];

字尾陣列sa[1..n]

表示1..n的乙個排列,滿足suffix(sa[i])

即:在所有字尾中排第i的是誰

名次陣列rank[1..n]

表示suffix(i)在字尾中的名次。

即:字尾i排第幾。

所以sa與rank為逆運算。

2.倍增演算法求字尾陣列。

//學過dc3邪教的自行離開。其實我是用字尾自動機構造的。

演算法非常好理解,就是用倍增求出每個字元開始長度為2^k的子字串排序

k==0..log2n上取整, 最後一遍處理時,子串相當於字尾。

**:

1

void

suffix()

23 }

view code

這裡有個小優化:若rank[sa[n]]已經為n時(所有串已經分出大小),就退出。

時間複雜度:o(n log n);不要嘗試跑1e6的構造資料(字元基本相同),常數巨大qaq

3.height陣列(最長公共字首lcp)

學會了構造,就要用字尾陣列搞事情了。

最經典的運用就是height陣列。

定義height[i]=suffix(sa[i])與suffix(sa[i-1])的最長公共字首。

對於suffix(j),suffix(k); rank[j]

他們的最長公共字首為min(height[rank[j]+1]..height[rank[k]]);

毛想想,由於序列是公升序的,那麼陣列的變換是不可逆(若sa[i],sa[i+1]的第j位發生了變化,那麼sa[i],sa[i+1]的第j位(或以前的位)一定也變了)。

那麼問題就是如何快速求出height陣列了。

定義h[i]=height[rank[i]] suffix(i)與前一名的最長公共字首。

舉個例子:

s=abaac

suffix=abaac, baac, aac, ac, c

sa=3,1,4,2,5

rank=2,4,1,3,5

height=0,1,1,0,0

h=1,0,0,1,0

h陣列有以下性質:h[i]>=h[i-1]+1;

證明:設suffix(k)是排在suffix(i-1)前一名的字尾(rank[k]=rank[i-1]-1)

則它們的最長公共字首為h[i-1],

若h[i-1]<2, 那麼顯然成立,當h[i-1]>=2時,s[i-1..i]==s[k..k+1],

且應為k在i-1的前一位,所以k+1排在i的前一位。

所以至少要共享後h[i-1]-1位

void

makeheight()

for (j=sa[rank[i]-1];(j+k<=l)&&(i+k<=l)&&(s[j+k]==s[i+k]);k++);

height[rank[i]]=k;}}

view code

有了height陣列,就可以用rmq求出lcp

例題:[poj2774]求兩個串的最長公共子串(l<100000)

解法:將兩串相連,在中間加乙個沒用到的字元,求出height陣列,在其中找乙個最大的height,且所指的兩個串乙個在空字元前乙個在空字元後。

字尾樹 字尾陣列

在字串處理當中,字尾樹和字尾陣列都是非常有力的工具,其中字尾樹大家了解得比較多,關於字尾陣列則很少見於國內的資料。其實字尾陣列是字尾樹的乙個非 常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也不太遜色,並且,它比字尾樹所占用的空間小很多。可以說,在資訊學競賽 中字尾...

字尾樹 字尾陣列

我們考慮將乙個串的所有字尾插入乙個trie中,得到的trie就是字尾trie。我們可以發現,樹上有分叉或者是字尾節點的點的個數是o l en o len o len 個,這個後面解釋,於是把沒有分支並且不是字尾節點的點壓縮到一起,就變成了字尾樹。不難發現,字尾樹可以表示該字串的所有子串。下面分析一下...

字尾陣列入門,字尾陣列模板整理

我自己懶得寫,就是想寫個部落格儲存下大佬的部落格位址 點這模板題 大佬的模板 include include include include include include include include include include include define inf 0x3f3f3f3f d...