BOJ

[백준 2941번/JAVA] 크로아티아 알파벳

syj0522 2024. 3. 11. 22:30

문제

백준 2941번
주어진 문자열이 몇 개의 크로아티아 알파벳으로 이루어져있는지 출력하는 문제

풀이 1) substring() 사용

연속된 두 개의 문자가 c=, c-, d-, lj, nj, s=, z=이면 하나로 세고,
연속된 세 개의 문자가 dz=이면 하나로 세어지도록 코드를 짜야 한다.

 

문자열을 입력받고, 알파벳의 갯수를 저장할 count 변수를 선언하고 0으로 초기화한다.

 

아래 세 경우를 str.length()번 반복한다.

  • 조건 1
    문자열의 인덱스를 초과하지 않는 범위에서 연속하는 두 문자로 이루어진 문자열을 추출한다.
    추출된 문자열이 c=, c-, ...와 같다면 다음 알파벳은 1개 뛰어넘고 세어야 하므로 i를 1증가시킨다.
  • 조건 2
    문자열의 인덱스를 초과하지 않는 범위에서 연속하는 세 문자로 이루어진 문자열을 추출한다.
    추출된 문자열이 dz=와 같다면 다음 알파벳은 2개 뛰어넘고 세어야 하므로 i를 2증가시킨다.
  • count 1증가

count를 출력한다.

코드

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

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));

        //연속된 두 개의 문자가 c= c- d- lj nj s= z=이면 하나로 센다.
        //연속된 세 개의 문자가 dz=이면 하나로 센다.

        String str = br.readLine();
        int count = 0;

        for(int i=0; i<str.length(); i++) {
            if(i<str.length()-1) {
                String s1 = str.substring(i,i+2);
                if(s1.equals("c=")||s1.equals("c-")||s1.equals("d-")||s1.equals("lj")||s1.equals("nj")||s1.equals("s=")||s1.equals("z=")) {
                    i++;
                }
            }
            if(i<str.length()-2) {
                String s2 = str.substring(i, i+3);
                if(s2.equals("dz=")) {
                    i+=2;
                }                
            }
            count++;
        }
        bw.write(count+" ");
        bw.close();
    }
}

풀이 2) StringBuilder 사용

로직은 풀이 1과 같으나, StringBuilder을 사용할 때는 주의할 점이 있다.

 

StringBuilder객체를 한 번 선언한 후 그 객체에 계속 append하면 뒤에 연달아 붙는다는 것에 유의하자.

 

처음에 StringBuilder 객체를 for문 밖에 선언해서 사용했는데, append 문제로 계속 오답처리가 되었다.
그래서 i++ 또는 i+=2가 실행된 다음에 객체를 비우는 메서드를 추가해보았는데 여전히 해결되지 않았다.

 

for문을 다시 실행할 때마다 StringBuilder 객체가 새로 생성되도록 선언문을 for문 아래로 옮겼더니 해결되었다.

 

for문 내에서도 StringBuilder 객체를 하나만 사용하려면 연속된 두 문자를 비교한 후 객체를 비우고 다시 append하여 연속된 세 문자를 비교해야한다는 점도 잊지 말자.

 

나는 StringBuilder객체 초기화가 안 먹혀서 그냥 별도의 객체를 두 번 생성해서 사용했다.

 

그러나 StringBuilder 객체를 매번 새로 생성해서 사용할 거면 StringBuilder의 이점을 무시한 구현방법 아닐까? 

그리고 성능면에서도 안 좋지 않을까? 라는 고민과 함께, 내일은 String과 StringBuilder에 대한 포스팅을 좀 더 보완해볼 생각이다. 포스팅을 마치고 나면 해당 코드도 업그레이드시킬 수 있지 않을까..?

코드

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

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));

        //연속된 두 개의 문자열이 c= c- d- lj nj s= z=이면 하나로 센다.
        //연속된 세 개의 문자열이 dz=이면 하나로 센다.

        String str = br.readLine();
        int count = 0;

        for(int i=0; i<str.length(); i++) {
            StringBuilder sb1 = new StringBuilder();
            if(i<str.length()-1) {
                sb1.append(str.charAt(i));
                sb1.append(str.charAt(i+1));
                String s = sb1.toString();
                if(s.equals("c=")||s.equals("c-")||s.equals("d-")||s.equals("lj")||s.equals("nj")||s.equals("s=")||s.equals("z=")) {
                    i++;
                }
            }
            StringBuilder sb2 = new StringBuilder();
            if(i<str.length()-2) {
                sb2.append(str.charAt(i));
                sb2.append(str.charAt(i+1));
                sb2.append(str.charAt(i+2));
                String s = sb2.toString();
                if(s.equals("dz=")) {
                    i+=2;
                }                
            }
            count++;
        }
        bw.write(count+" ");
        bw.close();
    }
}

 

위 - 풀이 1

아래 - 풀이 2

substring보다 StringBuilder가 성능이 더 좋다.

Note

  • ==equals()
    • String은 class이므로 ==연산자를 사용하면 주소값이 비교된다. 값 자체를 비교하려면 equals()메서드를 사용해야 한다.
  • StringBuilder 객체 사용 시 append에 유의하자. 아무것도 저장되지 않은 새로운 공간이 필요하다면 객체를 비우거나 새로 선언해야 한다.
  • if문이나 for문 안의 조건문을 계속 실수하게 된다. 더 신경쓰자