반응형
리뷰
KMP의 기초가 되는 문제, O(M+N)의 시간 복잡도로 해당 문제를 푸는게 놀라울 따름이다.
https://www.acmicpc.net/problem/1786
전역 변수
- str1, str2 : 원본 문자열 str1, 원본 문자열에서 패턴을 찾을 문자열 str2
- n, m, cnt : str1의 길이 n, str2의 길이 m, str1에서 str2를 찾은 개수 cnt
- lps, ans : 부분 문자열의 lps를 구할 정수형 벡터 lps, 찾은 인덱스를 저장할 정수형 벡터 ans
함수
1. getLPS
void getLPS(const string& str2)
패턴 문자열 str2에서 LPS를 구하기 위한 함수
- lps벡터를 m크기로 초기화 해준다. lps[0]은 0으로 초기화 해야하므로 일단 모두 0으로 초기화 해주었다.
- cur = 0, i = 1부터 시작하여 i가 str2의 길이 m보다 작을경우 while루프를 실행해 준다.
- 만약 str2[cur]과 str2[i]가 같을 경우 lps[i]를 cur + 1로 저장해 주고 cur과 i를 모두 증가시킨다.
- 아닐 경우 cur이 0보다 크다면 cur을 lps[cur - 1]로 변경해 준다.
- cur이 0일 경우엔 lps[i]를 0으로 설정하고 i를 증가시켜 준다.
2. KMP
void KMP(const string& str1, const string& str2)
KMP를 통해 원본 문자열에서 패턴 문자열을 찾아주는 함수
- i, j를 각각 str1, str2의 탐색 인덱스로 사용해 준다.
- i가 원본 문자열의 길이 n보다 작을 경우 while을 통해 루프를 돌아준다.
- 만약 str1[i]과 str2[j]가 같을 경우 i와 j를 모두 증가시켜 준다.
- 만약 j와 m이 동일할 경우 원본 문자열에서 패턴을 찾은 케이스이다.
- cnt를 증가시켜 주고 ans에 i - j + 1을 추가해 준다, 1-based-indexing이므로 1을 증가시켜 준 것이다.
- 이후 j를 lps[j - 1]로 변경해 준 뒤에 탐색을 계속 진행한다.
- 만약 j와 m이 다를 경우 i가 n보다 작고, str2[j]와 str1[i]가 다르고 j가 0이 아니라면 j를 lps[j - 1]로 변경해 준다.
- j가 0이라면 i를 증가 시킨 후에 탐색을 진행해 준다.
문제풀이
- 문자열에 띄워쓰기가 포함되어 있으므로 getline을 통해 str1과 str2를 입력 받아준다.
- n과 m에 각각 str1의 길이와 str2의 길이를 저장해 준다.
- getLPS 함수를 통해 str2의 LPS를 구해준 후 lps벡터에 그 값을 저장해 준다.
- KMP 함수를 통해 str1에서 str2가 몇번 찾을 수 있는지 개수와 인덱스 정보를 저장해 준다.
- 탐색을 마친 후 cnt를 출력해 주고 줄바꿈한 뒤에 공백을 기준으로 각각의 인덱스를 출력해 준다.
참고 사항
- KMP에서 i와 j가 증가된 상태에서 i가 n값을 넘어갈 수 있기 때문에 i < n를 조건문에 추가해 주어야 한다.
- str1과 str2모두 띄워쓰기가 포함될 수 있다, 두 문자열 모두 getline으로 입력 받아주어야 한다.
정답 코드
#include<iostream>
#include<string>
#include<vector>
using namespace std;
string str1, str2;
int n, m, cnt;
vector<int> lps, ans;
void getLPS(const string& str2) {
int cur = 0, i = 1;
lps.resize(m, 0);
while (i < m) {
if (str2[cur] == str2[i]) {
cur++;
lps[i] = cur;
i++;
}
else {
if (cur != 0) cur = lps[cur - 1];
else {
lps[i] = 0;
i++;
}
}
}
}
void KMP(const string& str1, const string& str2) {
int i = 0, j = 0;
while (i < n) {
if (str1[i] == str2[j]) {
i++;
j++;
}
if (j == m) {
cnt++;
ans.push_back(i - j + 1);
j = lps[j - 1];
}
else if (i < n && str2[j] != str1[i]) {
if (j != 0) j = lps[j - 1];
else i++;
}
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
getline(cin, str1);
getline(cin, str2);
n = str1.size(), m = str2.size();
getLPS(str2);
KMP(str1, str2);
cout << cnt << "\n";
for (const int& a : ans) cout << a << " ";
}
728x90
반응형
'알고리즘 공부 > C++' 카테고리의 다른 글
[G2] 백준 13334번 철로 C++ 우선순위 큐, 정렬, 스위핑 (0) | 2024.10.11 |
---|---|
[G3] 백준 1701번 Cubeditor C++ KMP, 문자열, 브루트포스 알고리즘 (1) | 2024.10.10 |
[G3] 백준 16934번 게임 닉네임 C++ 트라이, 문자열, 해시맵 (1) | 2024.10.10 |
[G3] 백준 7432번 디스크 트리 C++ 트라이, 문자열, DFS (1) | 2024.10.09 |
[G4] 백준 5052번 전화번호 목록 C++ 트라이, 문자열 (1) | 2024.10.08 |