백준 2941번: 크로아티아 알파벳

1) 문제 분석

  두 가지 방법이 떠올랐다. 하나는 단어의 문자를 처음부터 하나씩 읽어가면서 따지는 것이고 다른 하나는 문자열에서 크로아티아 알파벳에 해당되는 부분을 알파벳이 아닌 문자(여기서는 “?”)로 전부 바꿔주고, 마지막에 이 문자열의 길이를 출력해주는 것이다. 첫 번째 방법은 C 스타일이고 두 번째 방법은 C++의 string 메소드들도 쉽게 해결해 줄 수 있다.
  우선 두 번째 방법부터 보자면, 크로아티아 알파벳에 해당되는 문자열들(ex: “c=”, “nj”,…)을 배열에 넣어놓고, 이 배열의 각 원소(문자열)들이 입력된 단어에 들어가있는지 확인하고(find 메소드 사용) 그렇다면 이를 “?”로 바꿔준다(replace 메소드 사용). 예제 4번 처럼 같은 문자열이 한 단어에 여러 번 나타날 수 있으므로 find의 값이 입력 단어의 인덱스 범위를 넘어갈 때까지 같은 크로아티아 알파벳 문자열에 대해서 find 메소드를 반복해준다. 이 방법은 코드를 이해하기에도 쉽고 코드도 간결해지지만 단어가 훨씬 길어지고, 처리해야 하는 단어가 1개가 아니라 여러 개가 되면, find와 replace를 반복적으로 사용하기 때문에 효율이 떨어질 것 같았다.
  따라서 대신 첫 번째 방법은, 단어를 입력 받으면 단어의 첫 문자부터 차례로 읽어나가면서 크로아티아 알파벳에 해당하는 문자들이 있으면 한 문자로 카운트하고 그 문자들 이후의 문자를 다시 읽어나가는 식으로 문자의 총 개수를 구하는 방법이다. 이렇게 되면 단어의 문자들을 정확히 한 번만 읽어도 되고 문자들을 바꿀 필요도 없다.
  두 방법이 속도에서 어느 정도 차이 나는지 확인하기 위해 간단하게 실험을 해보았는데

ljes=njakljes=njakljes=njakljes=njakljes=njakljes=njakljes=njak

이라는 문자열에 대해 100번 반복하여 실행했을 때의 시간이 얼마나 걸리는지 측정해보았다(10번 반복). 첫 번째 방법은 (51, 45, 48, 27, 42, 28, 45, 39, 44, 30)ms가 나왔고, 두 번째 방법은 (510, 553, 645, 414, 585, 412, 418, 411, 545, 514)ms가 나왔다. 평균값을 계산해보면 각각 39.9ms와 500.7ms로 10배 이상의 차이가 있다.

2) 두 번째 방법 코드

#include<iostream>
#include <string>

using namespace std;
string alpha[] = {"c=", "c-", "dz=", "d-", "lj", "nj", "s=","z="};

int main(){
    ios_base::sync_with_stdio(false);
    string word;

    cin >> word;
    //replace all strings from alpha array with "?" in word
    for(int i=0; i<8; i++){
        int index = word.find(alpha[i]);
        //repeat replacement until alpha[i] string appears no more
        while(0<=index && index<word.length()){
            //replace alpha[i] with "?"
            word.replace(index, alpha[i].length(), "?");
            index = word.find(alpha[i]);
        }
    }
    //print out the length of the word
    cout << word.length();
}

3) 첫 번째 방법 코드

#include<stdio.h>

int main(){
    char word[102];
    int count = 0;  //total number of characters
    int length;     //length of the word

    fgets(word, sizeof(word),stdin);
    //find the length of the word
    for(length=0; word[length]!='\n' && word[length]!='\0'; length++) ;

    for(int i=0; i<length; i++){
        switch(word[i]){
 	    //"c=" or "c-"
            case 'c':
                if(i+1<length && (word[i+1]=='=' || word[i+1]=='-'))
                    i++;  //skip one character
                break;
	    //"dz="
            case 'd':
                if(i+2<length && word[i+1]=='z' && word[i+2]=='=')
                    i+=2; //skip two characters
                else if(i+1<length && word[i+1]=='-')
                    i++;  //skip one character
                break;
	    //"lj" or "nj"
            case 'l':
            case 'n':
                if(i+1<length && word[i+1]=='j')
                    i++;  //skip one character 
                break;
	    //"s=" or "z="
            case 's':
            case 'z':
                if(i+1<length && word[i+1]=='=')
                    i++; //skip one character
                break;
        }
	//count one character
        count++;
    }

    printf("%d",count);
}