문제 URL:
2941번: 크로아티아 알파벳
예전에는 운영체제에서 크로아티아 알파벳을 입력할 수가 없었다. 따라서, 다음과 같이 크로아티아 알파벳을 변경해서 입력했다. 크로아티아 알파벳 변경 č c= ć c- dž dz= đ d- lj lj nj nj š s= ž z=
www.acmicpc.net
다음 문제는 단어가 주어졌을 때, 몇 개의 크로아티아 알파벳으로 이루어져 있는지 출력하는 문제로,
프로그램 내에서 크로아티아 알파벳은 아래 표의 변경과 같이 입력한다.
| 크로아티아 알파벳 | 변경 |
| č | c= |
| ć | c- |
| dž | dz= |
| đ | d- |
| lj | lj |
| nj | nj |
| š | s= |
| ž | z= |
(dž는 무조건 하나의 알파벳으로 쓰이고, d와 ž가 분리된 것으로 보지 않는다. lj와 nj도 마찬가지이다.
위 목록에 없는 알파벳은 한 글자씩 센다.)
이 문제에서 가장 고민을 많이 한 부분은 아무래도 string 문자열에서 find() 함수로 크로아티아 알파벳을 찾은 뒤,
그 다음을 어떻게 진행하느냐였다.
find()함수가 부분 문자열과 일치하는 첫번째 위치만 반환하기 때문에
문자열을 모두 살펴보기 위해서는 코드를 조작해주어야했다.
가장 처음에는 erase() 함수를 이용하려고 했었다.
f 함수에서 find() 함수로 알파벳을 찾고, 찾은 알파벳을 erase() 함수를 이용하여 지운 뒤
문자열에 부분 문자열이 또 있는지 찾는걸 다시 반복하는식으로 코드를 작성하려했으나,
찾은 알파벳을 지우면 그 알파벳의 앞뒤 문자가 이어지는 경우가 있을 수 있다는 것을 깨달았다.
ex. ds=z= -> ('s='를 제거) -> dz=
(원래는 d와 z=로 분리되어야하나 문자가 이어져서 크로아티아 알파벳 dz=로 분류가 됨)
첫 번째 방법이 잘못되었다는 것을 깨닫고 두 번째로는 find() 함수에 부분 문자열과 인덱스 숫자를 함께 적고,
알파벳을 찾으면 알파벳의 다음 인덱스부터 다시 부분문자열을 찾는 코드를 작성하려 하였다.
하지만 이 역시 잘못된 코드였는데, 위와 같은 코드는 알파벳을 중복해서 세어준다는 오류가 있었다.
ex. dz=z=
(정상적으로는 dz=와 z=로 분리가 되어서 총 알파벳의 개수는 2개이나,
위와 같은 과정을 거치게 되면 z=와 일치하는 알파벳을 찾을 때 dz=안의 z=도 한 번 더 세어지게 된다.)
위와 같은 시행착오들을 겪고 다른 방법을 생각해냈는데, replace() 함수를 이용하는 방법이었다.
find() 함수를 통해 크로아티아 알파벳을 찾고, 찾은 알파벳을 replace() 함수를 이용하여
"A"(크로아티아 알파벳과 겹치지 않는 문자)로 대체해주면 오류 없이 출력 결과가 나오게 된다.
이 과정을 거친 코드는 아래와 같다.
#include<iostream>
#include<string>
using namespace std;
int f(const string al, string& s)
{
int count = 0;
while (true)
{
if (s.find(al) != string::npos)
{
count++;
s.replace(s.find(al), al.size(), "A");
}
else
break;
}
return count;
}
int main()
{
int count = 0;
string s;
cin >> s;
string list[8] = { "c=", "c-", "dz=", "d-", "lj", "nj", "s=", "z=" };
for (int i = 0; i < 8; i++)
{
string al = list[i];
if (f(al, s) != 0)
count += f(al, s);
}
cout << count + s.size();
}