728x90
이 문제는 I,O로 구성된 문자열 중 IOI 가 몇개 포함되어 있는지 갯수를 구하는 문제이다. 처음 단순 부르트포스 방식으로 접근했다면 당연히 만점을 받지 못했을 것이다. 서브테스크 1의 경우 N<=100, M<=10,000이기 때문에 부르트 포스 방식으로 문제를 풀어도 O(NM) = 1,000,000 으로 통과 가능하다. 하지만 서브테스크 2의 경우 N<=1,000,000 M<=1,000,000 이기 때문에 통과할 수 없다.
이 문제를 푸는 방법은 크게 두가지이다.
1. I의 위치(i)를 시작으로 i+1위치에 O, i+2위치에 I 가 있는지 확인해 나간다.
2. KMP 알고리즘을 이용하여 패턴 매칭을 활용하여 구한다.
간단한 방법은 1번을 활용한 풀이로 다행히 패턴이 규칙적이기 때문에 해결 가능한 방법이다. (이 문제 이외의 비슷한 문자열 탐색에는 사용할 수 없다)
#include<iostream>
#include<string>
using namespace std;
int n, m;
string s;
void solution()
{
int cnt = 0;
for(int i = 0; i < m; i++)
{
if(s[i] == 'O')
{
continue;
}
int k = 0;//IOI 갯수
while(s[i + 1] == 'O' && s[i + 2] == 'I')
{
k++;
if(k == n)
{
cnt++;
k--; // 오른쪽으로 +2만큼 이동했을때 k값 유지
}
i += 2;
}
}
cout << cnt;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m >> s;
solution();
}
다음은 KMP 알고리즘을 활용한 풀이이다. 자세한 알고리즘 설명은 여기를 확인하면 된다.
알고리즘 - KMP
안녕하세요. 오랜만에 문어체로 시작하는데요, 학부동안 배운 알고리즘 또는 배우지 못한 다양한 알고리즘 및 자료구조 이론을 정리해보려고 합니다. 설명 과정에 틀린 부분이나 추가해야할 부
devconf.tistory.com
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int n, m;
string s;
vector<int> getSkipTable(string pattern)
{
int p = pattern.size();
vector<int> skipTable(p, 0);
int begin = 1, matched = 0; // matched는 몇개가 맞는지 length를 나타낸다.
while(begin + matched < p)
{
if(pattern[matched] == pattern[begin + matched]) // matched는 접두부,begin+matched는 접미부를 나타낸다.
{
matched++;
skipTable[begin + matched - 1] = matched;
}
else
{
if(matched == 0)
{
begin++;
}
else
{
// KMP 문자열 탐색 알고리즘 과 동일하게 불일치 발생 시
// 매칭을 진행하면서 구했던 접두 접미사 길이 만큼 탐색을 건너뛸 수 있다
begin += matched - skipTable[matched - 1];
matched = skipTable[matched - 1];
}
}
}
return skipTable;
}
vector<int> kmpSearch()
{
string pattern;
vector<int> ret;
vector<int> skip_table;
for(int i = 0; i < 2 * n + 1; i++)
{
if(i % 2 == 0)
{
pattern.push_back('I');
}
else
{
pattern.push_back('O');
}
}
int originLength = s.size(), patternLength = pattern.size();
int begin = 0, matched = 0;
skip_table = getSkipTable(pattern);
while(begin <= originLength - patternLength)
{
if(matched < patternLength && s[begin + matched] == pattern[matched])
{
matched++;
if(matched == patternLength)
{
ret.push_back(begin);
}
}
else
{
if(matched == 0)
{
begin++;
}
else
{
begin += matched - skip_table[matched - 1];
matched = skip_table[matched - 1];
}
}
}
return ret;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cin >> n >> m >> s;
vector<int> result;
result = kmpSearch();
cout << result.size();
}
반응형
'알고리즘 > boj' 카테고리의 다른 글
BOJ 11725 트리의 부모 찾기 (0) | 2023.04.01 |
---|---|
BOJ 12865 평범한 배낭 (0) | 2023.03.20 |
BOJ 5430 AC (0) | 2023.03.07 |
BOJ 10026 적록색약 (0) | 2023.02.27 |
BOJ 9019 DSLR (0) | 2023.02.26 |