컴퓨터 사이언스/1고리즘
백준 1786 : 찾기
저세상 개발자
2021. 8. 9. 12:08
https://www.acmicpc.net/problem/1786
1786번: 찾기
첫째 줄에, T 중간에 P가 몇 번 나타나는지를 나타내는 음이 아닌 정수를 출력한다. 둘째 줄에는 P가 나타나는 위치를 차례대로 공백으로 구분해 출력한다. 예컨대, T의 i~i+m-1번 문자와 P의 1~m
www.acmicpc.net
KMP 그 자체인 문제다. 문제 설명에서도 KMP 알고리즘의 로직을 설명하고있다.
+) KMP 알고리즘 참고 자료
https://injae-kim.github.io/dev/2020/07/23/all-about-kmp-algorithm.html
Injae's devlog
현실의 문제를 해결하는 엔지니어
injae-kim.github.io
#include <iostream>
#include <vector>
#include <string>
using namespace std;
string p, t;
//pi 배열 업데이트
vector<int> getPi() {
//1번 인덱스부터 검사
int idx = 1, matched = 0;
vector<int> pi(p.size(), 0);
while (idx + matched < p.size()) {
//일치한다면 matched 증가 및 pi배열 갱신
if (p[idx + matched] == p[matched]) {
++matched;
pi[idx + matched - 1] = matched;
}
//일치하지 않는다면
else {
//하나도 일치하는게 없으면 단순히 시작 인덱스 증가
if (!matched) ++idx;
//일치하는 데이터가 있을 시 이미 확인된 공통 접두,접미사
//길이만큼 이동
else {
idx += matched - pi[matched - 1];
matched = pi[matched - 1];
}
}
}
return pi;
}
//src 문자열과 pattern 문자열 비교
//방법은 pi 배열 업데이트 방법과 동일
vector<int> kmp() {
int idx = 0, matched = 0;
vector<int> ret;
vector<int> pi = getPi();
while (idx + matched < t.size()) {
if (matched < p.size() &&
t[idx + matched] == p[matched]) {
++matched;
//매칭된 개수가 패턴 문자열의 길이와 같을 시
//정답 배열에 시작 인덱스 추가
if (matched >= p.size())
ret.push_back(idx);
}
else {
if (!matched) ++idx;
else {
idx += matched - pi[matched - 1];
matched = pi[matched - 1];
}
}
}
return ret;
}
void solution() {
getline(cin, t);
getline(cin, p);
vector<int> ans = kmp();
cout << ans.size() << '\n';
for (int i = 0; i < ans.size(); i++) {
cout << ans[i] + 1 << ' ';
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
solution();
return 0;
}
메모리: 9432 kb | 시간: 60 ms |
KMP는 발상 자체는 간단한 것 같으면서도 구현 방법을 보면 이게 이렇게 구현된다는게 신기하다는 생각이 든다.