티스토리 뷰
문제 링크
https://algospot.com/judge/problem/read/HABIT
algospot.com :: HABIT
말버릇 문제 정보 문제 대중 앞에서 연설이나 강의를 하는 사람들은 말 중간중간에 습관적으로 들어가는 말버릇들을 없애기 위해 많은 노력을 합니다. 강의를 하는 사람이 한 마디 할 때마다 "��
algospot.com
접미사 배열을 이용해서 푸는 문제입니다.
접미사 배열이란 문자열에서 나타날 수 있는 모든 접미사들을 사전순으로 정렬해 둔 배열을 말합니다.
banana 라는 문자열의 접미사는 아래와 같이 총 6개가 있습니다.

이 접미사들을 사전순으로 정렬을 하면 a가 가장 먼저오고 na가 가장 마지막에 오게됩니다.
이렇게 정렬된 각 접미사들의 전체 문자열 시작위치가 접미사 배열이 됩니다.
예시에서 접미사 a의 시작위치는 banana의 가장 마지막인 5가 되고
접미사 na의 시작위치는 4가 됩니다.

문제에서 부분 문자열이 k번 이상만큼 여러번 나오려면 항상 인접한 접미사들의 접두사로 나오게됩니다.
따라서 인접한 모든 접미사의 공통 접두사가 k번 이상 나오는지를 접미사 배열을 통해 확인하면 됩니다.
위에서 구한 접미사 배열을 순서대로 살펴보면
1번부터 3번까지의 접미사들의 접두사가 모두 a로 같기 때문에 s에서 가장 많이 나오는 부분 문자열이 됩니다.

문제 링크
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <string> | |
#include <algorithm> | |
#define endl '\n' | |
#define fastio cin.sync_with_stdio(false); cin.tie(nullptr) | |
using namespace std; | |
struct Comparator{ | |
const vector<int>& group; | |
int t; | |
Comparator(const vector<int>& _group, int _t): group(_group), t(_t) | |
{ | |
} | |
bool operator()(int a, int b){ | |
if(group[a] != group[b]) return group[a] < group[b]; | |
return group[a+t] < group[b+t]; | |
} | |
}; | |
//접미사 배열을 계산하는 맨버-마이어스 알고리즘 | |
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> perm(n); | |
for(int i=0;i<n;i++) | |
perm[i] = i; | |
while(t < n){ | |
Comparator compareUsing2T(group, t); | |
sort(perm.begin(), perm.end(), compareUsing2T); | |
t *= 2; | |
if(t >= n) break; | |
vector<int> newGroup(n+1); | |
newGroup[n] = -1; | |
newGroup[perm[0]] = 0; | |
for(int i=1;i<n;++i){ | |
if(compareUsing2T(perm[i-1], perm[i])) | |
newGroup[perm[i]] = newGroup[perm[i-1]] + 1; | |
else | |
newGroup[perm[i]] = newGroup[perm[i-1]]; | |
} | |
group = newGroup; | |
} | |
return perm; | |
} | |
//s[i..]와 s[j..]의 공통 접두사의 최대 길이를 계산한다. | |
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; | |
} | |
//k번 이상 출현하는 s의 부분 문자열 중 최대 길이를 찾는다. | |
int longestPrefix(int k, const string& s){ | |
vector<int> a = getSuffixArray(s); | |
int ret = 0; | |
for(int i=0;i+k<=s.size();++i) | |
ret = max(ret, commonPrefix(s, a[i], a[i+k-1])); | |
return ret; | |
} | |
int main(){ | |
fastio; | |
int _; | |
cin >> _; | |
while(_--){ | |
int k; | |
string s; | |
cin >> k >> s; | |
cout << longestPrefix(k, s) << endl; | |
} | |
return 0; | |
} |
'Coding Test > 알고스팟' 카테고리의 다른 글
[C++] 알고스팟/문자열 검색 - Jaeha's Safe (0) | 2020.09.03 |
---|---|
[C++] 알고스팟/문자열 검색 - 팰린드롬 만들기 (0) | 2020.09.02 |
[C++] 알고스팟/문자열 검색 - 작명하기 (0) | 2020.09.01 |
[C++] 알고스팟/탐욕법 - 문자열 합치기 (0) | 2020.08.31 |
[C++] 알고스팟/탐욕법 - Microwaving Lunch Boxes (0) | 2020.08.28 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 두니발 박사의 탈옥
- 하둡
- hive
- 스파크
- 종만북
- 삼각형 위의 최대 경로
- 알고스팟
- import
- 배열과 문자열
- HDFS
- 완전탐색
- Hadoop
- Sqoop
- 출전 순서 정하기
- Jaeha's Safe
- microwaving lunch boxes
- Django
- 코딩인터뷰 완전분석
- 합친 lis
- 백준
- 팰린드롬 구하기
- 하이브
- pyspark
- 분할정복
- 삼각형 위의 최대 경로 수 세기
- HiveQL
- C++
- 외발 뛰기
- 2225
- python
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
글 보관함