1 분 소요

IOIOI (백준 Silver 1)

https://www.acmicpc.net/problem/5525

N 개가 주어질 때, PN = IOIOI…OI (O가 N개) 라 한다
주어지는 문자열 S 에서
PN의 개수를 구하는 문제

제출 코드

#include<iostream>
#include<string>

using namespace std;

int main()
{
	int n,m;
	cin >> n >> m;
	string str;
	cin >> str;

	string findStr = "I";
	for (int i = 0; i < n; i++)
		findStr += "OI";

	int result = 0;

	int fSize = findStr.size();
    auto sBegin = str.begin();

	for (int i = 0; i < m - fSize + 1; i++)
	{
		if (str[i] == 'I')
		{
			string temp(sBegin + i, sBegin + i + fSize);
			if (temp == findStr)
				result++;
		}
	}

	cout << result;
	return 0;
}

틀린 이유?

처음에는 이 코드가 시간초과(50점)이 발생한 이유를 알 수 없었다
겉보기에는 ‘반복문’을 한번만 도니
O(N) 이라 생각하였다

(혹시 몰라 투 포인터를 써봤지만 역시 틀렸다)

그런데 곰곰히 생각해보니
‘문자열’을 저런식으로 ‘생성’하는 것과
‘문자열을’ 비교 하는 것이 과연 O(1)일까?

  • 저런 식의 String 생성 방법 과
    substr 은 모두 O(N)의 시간 복잡도를 지닌다
    (문자열의 ‘길이’를 재고 index 부터 거기까지 잘라야 하므로)

  • 또한 문자열 == 비교와
    compare 역시 O(N)의 시간 복잡도를 지닌다
    (일일이 문자를 비교하며 확인해야 하므로)

따라서 사실상 저 코드는
O(N^2)였다…

최종 코드

#include<iostream>
#include<string>

using namespace std;

int main()
{
	int n, m;
	cin >> n >> m;
	string str;
	cin >> str;

	int result = 0;
	int count = 0;

	for (int i = 1; i < m - 1; i++)
	{
		if (str[i - 1] == 'I' &&
			str[i] == 'O' &&
			str[i + 1] == 'I')
		{
			count++;
			if (count >= n)
				result++;
			i++;
		}
		else
		{
			count = 0;
		}
	}

	cout << result;
	return 0;
}

코드 해설

사실상 연속된 ‘IOI’ 패턴의 개수를 구한 후
그 연속된 패턴의 개수가 n을 넘어가게 되면 result++ 해주는 방식이다
(이 때, IOI가 존재한다면 i를 2번 더해줘야 한다)

그 외에는 연속되지 않게 되므로 count를 초기화

결과

Image

좀 많이 해맸다
아무래도 ‘구현’ 자체는 간단하였으나
string에 대한 연산이 그렇게 가볍게 이뤄지지 않는다는 사실을
다시 깨닫고 갈 수 있는 문제였다

댓글남기기