알고리즘 문제풀이
[Algospot] 알고스팟 작명하기(NAMING) 문제풀이(C++)
도리컴
2023. 2. 27. 01:55
반응형
예전에 배웠던 KMP 알고리즘 다시 떠올릴 수 있는 문제였음
KMP 알고리즘 핵심 :
1. 문자열 검색 도중 일치하는 부분이 나왔고, 그 다음문자가 불일치하면 -> 다음 비교위치는 [ 검색문자열에서 일치한 부분 ] 에서의 [ 최대길이 접두/접미사 ] 부분 이후부터라는 점
2. 검색문자열 S에 대해 S[...i] 까지의 부분문자열의 최대 접두/접미사 길이를 pi[i]라 할 때, pi배열을 KMP개념을 이용하여 빠르게 구할 수 있음.
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#include<iostream>
#include<string>
#include<vector>
using namespace std;
/*
<문제> - 500ms, 65536kb 제한
두 이름이 주어졌을 때, 두 이름을 합한 것에서
접두사도 되고 접미사도 되는 문자열들을 모두 찾기
<입력>
두 줄에 걸쳐 아버지, 어머니 이름 주어짐(합쳐서 40만 안넘음)
<출력>
접두/접미사가 되는 문자열들 길이를 오름차순으로 출력(공백하나 두고)
<풀이>
1. 아이디어 - KMP 이용 / pi[n]을 정의한 다음,
전체문자열 중에 검색하는 비교문자열 S에 대해 S[n]번째까지 동일한 경우에서,
다음 문자가 다르면 -> 이 문자의 다음 비교문자는 S[pi[n]]이 되는 것을 이용
- pi배열 생성 - pi[n] : 기존 문자열의 부분문자열 S[...n] 중 가장 긴 접두/접미사의 길이 / 이거 생성 O(N+H)에 가능(이것도 KMP알고리즘 이용)
- 검색문자위치와 비교문자위치 / 검색문자위치는 순차적으로 계속 증가할거고, 비교문자위치는 계속 변할거
- 문자열 일치할 경우 : count++하며 계속 탐색
- 문자열 불일치할 경우 : 비교문자열 S에 대해, S[pi[count]]부터 다시 탐색, count=pi[count]
2. 시간복잡도
- O(M+N) / M은 총 문자열, N은 비교문자열
3. 변수
- int now : 현재 비교위치
- string name : 입력문자열
*/
int main() {
string a, b; cin >> a >> b;
string name = a + b;
vector<int> pi(name.size(), 0);
//pi배열 생성
int now = 0; //현재 비교위치
for (int i = 1; i < name.size(); i++) { //i : 검색위치
while (now > 0 && name[now] != name[i]) //now가 0이면 현재 비교대상이 처음문자이므로, name에서 다음 문자로 넘어감
now = pi[now - 1]; // 현재 비교대상 : S[...now-1] 에서 최대길이 접두/접미사 다음위치
if (name[now] == name[i]) pi[i] = ++now; //현재 비교대상이 일치하면 p[i]값 수정한 후 다음 위치로 이동
}
//pi저장 완료
now = name.size(); //현재 위치 - 처음엔 문자열 전체개수가 접두/접미사이기 때문에 이렇게 들어감
vector<int> ans;
while (now > 0) {
ans.push_back(now);
now = pi[now - 1];
}
for (int i = ans.size() - 1; i >= 0; i--)
cout << ans[i] << " ";
return 0;
}
|
cs |

반응형