와드의 블로그

2941번: 크로아티아 알파벳 본문

PS/B.O.J

2941번: 크로아티아 알파벳

Ward 2026. 4. 10. 01:31

문제

예전에는 운영체제에서 크로아티아 알파벳을 입력할 수가 없어서, 다음과 같이 변경하여 입력했습니다.

  • c= (č)
  • c- (ć)
  • dz= (dž)
  • d- (đ)
  • lj (lj)
  • nj (nj)
  • s= (š)
  • z= (ž)

단어가 주어졌을 때, 이 단어가 몇 개의 크로아티아 알파벳으로 이루어져 있는지 구하는 프로그램을 작성하는 문제입니다. 목록에 없는 알파벳은 한 글자씩 센다고 가정합니다.

  • 입력: 첫째 줄에 최대 100글자의 단어가 주어집니다. 알파벳 소문자와 '-', '='로만 이루어져 있습니다.
  • 출력: 입력으로 주어진 단어가 몇 개의 크로아티아 알파벳으로 이루어져 있는지 출력합니다.

링크: https://www.acmicpc.net/problem/2941

풀이 1: 인덱스 조작과 조건문을 활용한 순차 탐색

문자열을 처음부터 끝까지 한 번 순회하면서, 특정 문자를 만났을 때 바로 뒤의 문자들을 확인(Lookahead)하여 크로아티아 알파벳 묶음을 찾아내는 직관적인 시뮬레이션 방식입니다.

  • 인덱스(idx) 기반 탐색: for문 대신 while문과 idx 변수를 사용하여, 여러 글자가 하나의 알파벳으로 취급될 때 인덱스를 유연하게 건너뛸 수 있도록 설계합니다.
  • 미리 보기(Lookahead) 및 경계 검사:
    • 현재 문자 c가 크로아티아 알파벳의 시작 문자인 c, d, l, n, s, z 중 하나라면, 이어지는 다음 문자를 확인합니다.
    • 이때 StringIndexOutOfBoundsException 오류를 방지하기 위해 반드시 idx < s.length() - 1 (두 글자 확인 시) 또는 idx < s.length() - 2 (세 글자인 dz= 확인 시)와 같이 안전하게 문자열 길이를 검사합니다.
  • 인덱스 건너뛰기:
    • 만약 조건을 만족하여 두 글자가 하나의 알파벳으로 묶인다면, idx += 1을 통해 다음 문자를 건너뜁니다.
    • 세 글자(dz=)가 묶인다면 idx += 2를 통해 두 문자를 건너뜁니다.
  • 정답 카운트: 분기문을 통과한 후 기본적으로 idx++가 한 번 더 실행되므로 다음 검사 위치로 알맞게 이동되며, 어떤 경우든 알파벳 하나를 센 것이므로 ans++를 수행합니다.

코드 1

import java.io.*;
import java.util.*;

public class Main {
    public static void main(String[] args) throws IOException {
       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
       BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

       String s = br.readLine();

       int ans = 0;
       int idx = 0;
       
       while (idx < s.length()) {
          char c = s.charAt(idx);
          
          if (c == 'c') {
             if (idx < s.length() - 1 && (s.charAt(idx + 1) == '=' || s.charAt(idx + 1) == '-')) {
                idx += 1;
             }
          } else if (c == 'd') {
             if (idx < s.length() - 1 && s.charAt(idx + 1) == '-') {
                idx += 1;
             } else if (idx < s.length() - 2 && s.charAt(idx + 1) == 'z' && s.charAt(idx + 2) == '=') {
                idx += 2;
             }
          } else if (c == 'l') {
             if (idx < s.length() - 1 && s.charAt(idx + 1) == 'j') {
                idx += 1;
             }
          } else if (c == 'n') {
             if (idx < s.length() - 1 && s.charAt(idx + 1) == 'j') {
                idx += 1;
             }
          } else if (c == 's') {
             if (idx < s.length() - 1 && s.charAt(idx + 1) == '=') {
                idx += 1;
             }
          } else if (c == 'z') {
             if (idx < s.length() - 1 && s.charAt(idx + 1) == '=') {
                idx += 1;
             }
          }
          
          idx++;
          ans++;
       }

       bw.write(ans + "");

       bw.flush();
    }
}

풀이 2: replaceAll 메서드를 활용한 문자열 치환

자바의 내장 문자열 치환 메서드인 replaceAll(또는 replace)을 활용하여, 코드를 극단적으로 단축시키는 방식입니다.

  • 배열 선언: 8개의 크로아티아 알파벳을 문자열 배열(croatian)에 미리 정의합니다.
  • 문자열 치환: 배열을 순회하면서 입력받은 문자열 s 내부에 크로아티아 알파벳과 일치하는 패턴이 있다면, 이를 임의의 한 글자(예: "a" 또는 "*" 등)로 전부 치환합니다.
    • 예: ljes=njak -> aes=njak (lj 치환) -> aea=njak (s= 치환) -> aeaaak (nj 치환)
  • 길이 도출: 모든 치환이 끝나면 크로아티아 알파벳은 각각 한 글자로 뭉쳐지고, 나머지 일반 알파벳도 원래 한 글자이므로, 최종적으로 남은 문자열의 길이(s.length())가 곧 전체 알파벳의 개수가 됩니다.

코드 2

import java.io.*;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String s = br.readLine();
        
        // 탐색할 크로아티아 알파벳 목록
        String[] croatian = {"c=", "c-", "dz=", "d-", "lj", "nj", "s=", "z="};
        
        // 목록을 순회하며 일치하는 문자열을 한 글자("a")로 치환
        for (String val : croatian) {
            s = s.replaceAll(val, "a");
        }
        
        // 치환이 완료된 문자열의 길이가 정답
        System.out.println(s.length());
    }
}

알고리즘 분류

구현 (Implementation), 문자열 (String)

'PS > B.O.J' 카테고리의 다른 글

1969번: DNA  (0) 2026.04.10
3613번: Java vs C++  (0) 2026.04.10
1929번: 소수 구하기  (0) 2026.04.08
단어 나누기  (0) 2026.04.07
16637번: 괄호 추가하기  (0) 2026.04.06