Kyopro Library
 
読み取り中…
検索中…
一致する文字列を見つけられません
suffix_array.hpp
[詳解]
1#pragma once
2#include"../../kyopro_library/template.hpp"
3
4/// @brief Suffix Array
5/// @brief `sa[i] = j <-> s[j:] が辞書順 i 番目`
6/// @brief O(n log(n))
7/// @ref https://wk1080id.hatenablog.com/entry/2018/12/25/005926
8template<int C=256>
9vector<int> SuffixArray(string s) {
10 s.push_back('$');
11 int n=s.size();
12 vector<int> p(n), c(n), cnt(max(n,C),0);
13 //p[i] := 辞書順 i 番目のインデックス
14 //c[i] := インデックス i の部分文字列の同値類
15
16 //2^0,2^1,...,2^k,... をやる
17 //k=0
18 for(int i=0; i<n; i++) cnt[s[i]]++;
19 for(int i=1; i<cnt.size(); i++) cnt[i]+=cnt[i-1];
20 //辞書順 = 累積和の小さい順 になる
21 for(int i=0; i<n; i++) p[--cnt[s[i]]]=i;
22 //同値類を計算する
23 c[p[0]]=0;
24 for(int i=1; i<n; i++) {
25 c[p[i]]=c[p[i-1]];
26 if(s[p[i]]!=s[p[i-1]]) c[p[i]]++;
27 }
28
29 vector<int> np(n),nc(n);
30 for(int k=0; (1<<k)<n; k++) {
31 //k を使って、(c[i],c[i+2^k]) でソート、 p[i]-=2^k でできる
32 //c[i+2^k] でソート
33 for(int i=0; i<n; i++) np[i]=p[i]-(1<<k),(np[i]+=n)%=n;
34 fill(cnt.begin(),cnt.end(),0);
35 for(int i=0; i<n; i++) cnt[c[np[i]]]++;
36 for(int i=1; i<cnt.size(); i++) cnt[i]+=cnt[i-1];
37 for(ll i=n-1; i>=0; i--) p[--cnt[c[np[i]]]]=np[i];
38 //同値類
39 nc[p[0]]=0;
40 for(int i=1; i<n; i++) {
41 nc[p[i]]=nc[p[i-1]];
42 if(c[p[i]]!=c[p[i-1]] || c[(p[i]+(1<<k))%n]!=c[(p[i-1]+(1<<k))%n]) nc[p[i]]++;
43 }
44 swap(c,nc);
45 }
46
47 p.erase(p.begin());
48 return p;
49}
vector< int > SuffixArray(string s)
Suffix Array