아래 소스코드는 접미사 배열을 구하는 함수.
어떤 문자열의 모든 접미사를 사전순으로 정렬해둔것.
출처 : http://blog.myungwoo.kr/57
사진 뜻.
0번째 접미사 배열은 아래 문자열 banana의 5번째부터 끝까지다. == a
1번째 접미사 배열은 아래 문자열 banana의 3번째부터 끝까지다. == ana
2 : anana, 3 : banana, 4 : na, 5 : nana
*같은 문자로 시작하는 접미사 배열은 인접해 있음. a로 시작하는 접미사배열은 0,1,2의 경우.
b로 시작하는 접미사배열은 3, n은 4,5에 있다.
LCP 란 i번째 접미사와 i-1번째 접미사의 '가장 긴 공통 접두사의 길이'라고 한다.
ex) i번째 접미사 : a, i+1번째 접미사 : ana라고 하면 lcp는 1.
ana, anana의 lcp는 3(ana의 3). anana와 banana는 0이다. 앞에서 시작하는게 a와 b로 다르기 때문.
이런식. 종만북소스.
#include<list> #include<iostream> #include<string> #include<vector> #include<queue> #include <algorithm> using namespace std; vector<int> getSuffixArray(const string& s) { int n=s.size(); int t=1; vector<int> group(n+1); for(int i=0;i<n;i++) group[i]=s[i]; group[n] = -1; vector<int> suffix(n); for(int i=0;i<n;i++) suffix[i] = i; while(t<n) { auto cmp = [&group, t](int a, int b) { if(group[a] != group[b]) return group[a] < group[b]; return group[a+t] < group[b+t]; }; sort(suffix.begin(), suffix.end(), cmp); t *= 2; if(t>=n) break; vector<int> newGroup(n+1); newGroup[n] = -1; newGroup[suffix[0]]=0; for(int i=1;i<n;i++) { if(cmp(suffix[i-1],suffix[i])) newGroup[suffix[i]]=newGroup[suffix[i-1]]+1; else newGroup[suffix[i]]=newGroup[suffix[i-1]]; } group = newGroup; } return suffix; } int commonPrefix(const string &s, int i, int j) { int k=0; while(i<s.size() && j<s.size() && s[i]==s[j]) { i++; j++; k++; } return k; } int countSubstrings(const string& s) { vector<int> a = getSuffixArray(s); int ret = 0; int n = s.size(); for(int i=0;i<a.size();i++) { int cp = 0; if(i>0) cp = commonPrefix(s,a[i-1],a[i]); if(cp > ret) ret = cp; cout<<"lcp = "<<cp<<endl; //ret += s.size() - a[i] - cp; } return ret; } int main() { string a; cin>>a; vector<int> suffix = getSuffixArray(a); for(int i=0;i<suffix.size();i++) cout<<i<<" = "<<suffix[i]<<endl; cout<<countSubstrings(a)<<endl; return 0; }
위에 적은 블로그에서 가져온 소스. 더 빠르다. 참고용
#include<list> #include<iostream> #include<string> #include<vector> #include<queue> #include <cstdio> #include <cstring> using namespace std; #define MAXN 500005 int N,SA[MAXN],lcp[MAXN]; char S[MAXN]; void SuffixArray() { int i,j,k; int m = 27; vector <int> cnt(max(N,m)+1,0),x(N+1,0),y(N+1,0); for (i=1;i<=N;i++) { if(S[i]=='$') cnt[x[i] = m]++; else cnt[x[i] = S[i]-'A'+1]++; } for (i=1;i<=m;i++) cnt[i] += cnt[i-1]; for (i=N;i;i--) SA[cnt[x[i]]--] = i; for (int len=1,p=1;p<N;len<<=1,m=p) { for (p=0,i=N-len;++i<=N;) y[++p] = i; for (i=1;i<=N;i++) if (SA[i] > len) y[++p] = SA[i]-len; for (i=0;i<=m;i++) cnt[i] = 0; for (i=1;i<=N;i++) cnt[x[y[i]]]++; for (i=1;i<=m;i++) cnt[i] += cnt[i-1]; for (i=N;i;i--) SA[cnt[x[y[i]]]--] = y[i]; swap(x,y); p = 1; x[SA[1]] = 1; for (i=1;i<N;i++) x[SA[i+1]] = SA[i]+len <= N && SA[i+1]+len <= N && y[SA[i]] == y[SA[i+1]] && y[SA[i]+len] == y[SA[i+1]+len] ? p : ++p; } } void LCP() { int i,j,k=0; vector <int> rank(N+1,0); for (i=1;i<=N;i++) rank[SA[i]] = i; for (i=1;i<=N;lcp[rank[i++]]=k) for (k?k--:0,j=SA[rank[i]-1];S[i+k]==S[j+k];k++); } int main() { int i,max=-1; scanf("%s",S+1); //S[strlen(S+1)+1]='$'; scanf("%s",S+1+strlen(S+1)); N = strlen(S+1); cout<<"str = "<<S+1<<endl<<"suffix = "; SuffixArray(); for(int i=1;i<=N;i++) cout<<SA[i]<<" "; cout<<endl<<"lcp = "; LCP(); for (i=1;i<=N;i++) { cout<<lcp[i]<<" "; if(lcp[i]>max) max=lcp[i]; } cout<<endl<<max<<endl; return 0; }
'algorithm > theory' 카테고리의 다른 글
상호 배타적 집합.(Disjoint-set) (0) | 2016.09.27 |
---|---|
트라이(Trie), 아호코라식 (0) | 2016.09.26 |
소수 구하기.(에라토스테네스의 체, 앳킨의 체, 등등) (0) | 2016.09.22 |
이분 매칭 (0) | 2016.09.13 |
네트워크 유량 (0) | 2016.09.13 |