레야몬
[C++] 9248번 Suffix Array - 문자열, 접미사 배열과 lcp 배열 본문
1. 문제
- 길이가 50만보다 작거나 같은 문자열이 주어졌을 때, Suffix Array와 LCP Array를 구하는 프로그램을 작성하시오.
<입력>
- -1- 알파벳 소문자로만 이루어진 문자열 S가 주어진다. S의 길이는 50만보다 작거나 같다.
<출력>
- -1- Suffix Array
- -2- LCP Array를 출력한다. LCP Array의 첫 값은 항상 'x'이다.
2. 재정의
- X
3. 해결방법
- 맨버-마이아스 알고리즘(Manber-Myers Algorithm), kasai 알고리즘을 이용한다.
4. 실수한 점, 개선할 점
- Manber-Myers Algorithm에서 정렬을 일반적인 sort로 구현하면 시간 복잡도가 \(O(nlgn^{2})\)이 되는데 이를 counting sort로 구현하면 \(O(nlgn)\)으로 줄일 수 있다. (이해하는 데 많이 힘들었어요...ㅜㅜ)
<코드>
#include <iostream>
#include <algorithm>
#include <string.h>
const int MAX_N = 500002;
using namespace std;
//문자열과 그 길이
char str[MAX_N];
int N;
//suffix array 알고리즘
//탐색할 위치
int t;
//그룹과 tmp 그룹, suffix array
int g[MAX_N], tg[MAX_N], SA[MAX_N];
//LCP 알고리즘
//i번째 문자열이 suffix array에 위치한 순서
int RANK[MAX_N];
//LCP 배열
int LCP[MAX_N];
bool cmp(int x, int y) {
//배열의 크기를 넘어가는 것을 방지
x = min(x, N), y = min(y, N);
//그룹 번호가 같다면
if(g[x] == g[y])
return g[x+t] < g[y+t];
//그룹 번호가 다르다면
return g[x] < g[y];
}
void getSA() {
t = 1;
N = (int)strlen(str);
//첫 글자 그룹을 정해주는 전처리
for(int i=0; i<N; i++) {
SA[i] = i;
g[i] = str[i] - 'a';
}
//1, 2, 4, 8...씩 단어의 길이보다 작은 경우를 탐색
//배열의 x+y>=n이면 -1을 넘겨줌으로써 항상 앞에 오도록 한다
g[N] = -1;
while(t <= N) {
//그룹에 의한 정렬
sort(SA, SA+N, cmp);
//다음 그룹 배정
for(int i=1; i<N; i++) {
//그룹이 다를 경우 다음 그룹 번호 할당
if(cmp(SA[i-1], SA[i]))
tg[SA[i]] = tg[SA[i-1]] + 1;
//그룹이 같을 경우 같은 그룹 번호 할당
else
tg[SA[i]] = tg[SA[i-1]];
}
//새로운 그룹 할당
for(int i=0; i<N; i++)
g[i] = tg[i];
t <<= 1;
}
}
void getLCP() {
//RANK 배열에 i번째 문자열이 suffix array에 위치한 순서 대입
for(int i=0; i<N; i++)
RANK[SA[i]] = i;
//탐색한 곳까지 같은 문자열 길이
int match = 0;
for(int i=0; i<N; i++) {
int k = RANK[i];
if(k) {
//suffix array에서 인접한 문자열의 lcp를 구한다.
int j = SA[k-1];
while(str[j+match] == str[i+match])
match++;
LCP[k] = match;
//제일 앞 한 문자를 빼준 두 문자열의 LCP는 match-1이다.
if(match)
match--;
}
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> str;
//suffix array 구하기
getSA();
//LCP 구하기
getLCP();
for(int i=0; i<N; i++)
cout << SA[i]+1 << ' ';
cout << '\n';
cout << 'x' << ' ';
for(int i=1; i<N; i++)
cout << LCP[i] << ' ';
return 0;
}
가면 갈수록 코드 길이가 늘어나고 있다. 무의식 중에 코드 길이가 점점 증가하고 있는 것이다.... 어떡하지..ㅎㅎ;;
<Suffix Array와 Manber-Myers Algorithm>
접미사 배열(Suffix Array)
Suffix Array란, 문자열 S가 있을 때 그 접미사들을 정렬해 놓은 배열이다. 예를 들어, 문자열 S=banana의 접미사는 아래와 같이 총 6개가 있다.Suffixibanana1anana2nana3ana4na5a6이를 Suffix 순으로 정렬하면 아
www.crocus.co.kr
<LCP와 Kasai Algorithm - 1>
https://www.crocus.co.kr/614?category=209527
LCP 알고리즘(Longest Common Prefix)
LCP (Longest Common Prefix) 알고리즘이란? LCP는 두 접미사의 최대 공통 접두사의 길이를 의미한다. LCP를 이해하기 위해서는 아래 링크의 내용을 이해하여야 한다. 물론 LCP를 공부하기 위해 찾아온 사
www.crocus.co.kr
<LCP와 Kasai Algorithm - 2>
https://robustflame.tistory.com/entry/Suffix-Array-LCP-Array
Suffix Array, LCP Array
Suffix Array 접미사 배열(suffix array)는 어떤 문자열 S의 모든 접미사를 사전순으로 정렬해둔 것으로, 보통 각 접미사의 시작 위치를 저장하는 정수 배열로 구현된다. 길이가 \(n\)인 문자열의 접미사
robustflame.tistory.com
<Manber-Myers Algorithm을 Counting Sort로 구현하기>
[문자열] 접미사배열(Suffix Array)과 LCP(Longest Common Prefix), Counting Sort 정리
cultivo-hy.github.io
<pair<int, int> Counting Sort 하는 법>
https://plzrun.tistory.com/entry/Counting-Sort-Radix-Sort
Counting Sort & Radix Sort
Counting Sort & Radix Sort 오랜만에 포스팅을 해보려한다. 해당 정렬방법은 O(N)만에 수행이 가능하다. 아마 이 정렬방법을 모르는 사람은 거의 없을거고.. counting sort도 다 짤줄 안다고 생각하겠지만, P
plzrun.tistory.com
<Suffix Array를 Counting Sort로 구현한 코드>
https://devbelly.tistory.com/38
[백준 9248] Suffix Array
문제 https://www.acmicpc.net/problem/9248 알고리즘 Suffix Array 풀이 문자열에서 가장 어려운 알고리즘인 Suffix Array입니다. 이 글에선 제가 해당 알고리즘을 공부할 때 어려웠던 부분 및 이해하기 위한 선
devbelly.tistory.com
※현재 고등학교 등교 중인 학생입니다. 이제 알고리즘을 본격적으로 공부하기 시작해서 아직 초보입니다. 혹시 제가 잘못 알고 있는 점이나 더 좋은 풀이 방법이 있어 댓글에 남겨주시면 감사히 하나하나 열심히 읽어보겠습니다. 좋아요, 단순한 댓글 한마디라도 저에겐 큰 힘이 됩니다! 감사합니다.
'알고리즘 > 백준' 카테고리의 다른 글
[C++] 3033번 가장 긴 문자열 - 문자열, 해싱, 접미사 배열과 lcp 배열, 라빈-카프 (0) | 2022.11.08 |
---|---|
[C++] 1605번 반복 부분문자열 - 문자열, 해싱, 접미사 배열과 lcp 배열, 라빈-카프 (0) | 2022.11.08 |
[C++] 16975번 수열과 쿼리 21 - 자료 구조, 세그먼트 트리, 느리게 갱신되는 세그먼트 트리 (0) | 2022.11.04 |
[C++] 10999번 구간 합 구하기 2 - 자료 구조, 세그먼트 트리, 느리게 갱신되는 세그먼트 트리 (0) | 2022.11.04 |
[C++] 11377번 열혈강호 3 - 최대 유량, 이분 매칭 (0) | 2022.11.03 |