백준 놀라운 문자열

KIMYEONGJUN·2025년 9월 16일
0
post-thumbnail

문제

내가 생각했을때 문제에서 원하는부분

입력의 각 줄에는 알파벳 대문자로만 구성된 문자열이 주어진다.
모든 문자열의 길이는 80을 넘지 않으며, 입력의 마지막 줄에는 마지막을 나타내는 *가 주어진다.
입력은 마지막 줄을 포함해서 101줄을 넘지 않는다.

각 줄에 이 문자열이 놀라운(surprising) 문자열인지 아닌지를 아래의 예제와 같이 출력한다.

내가 이 문제를 보고 생각해본 부분

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));: 콘솔 입력을 처리하기 위한 BufferedReader 객체를 생성한다. 
이 객체는 프로그램이 끝날 때 명시적으로 닫아주어야 하는 리소스이다.
while(!(line = br.readLine()).equals("*")): 이 while 루프는 입력이 "*" 문자열이 될 때까지 계속 실행된다. 
문제에서 "*"는 입력의 종료를 나타내는 지시자이다.
br.readLine(): BufferedReader를 사용하여 한 줄의 문자열을 읽고, 그 문자열을 line 변수에 할당한다.
if(isSurprising(line)) { ... } else { ... }: 읽어온 line 문자열을 isSurprising 메서드에 넘겨 "놀라운 문자열"인지 판별하고, 그 결과에 따라 적절한 출력 메시지를 생성하여 콘솔에 출력한다.
br.close();: 새롭게 추가된 중요한 부분이다.
프로그램이 모든 입력을 처리하고 나면, 더 이상 BufferedReader를 사용할 필요가 없다. 
이때 close() 메서드를 호출하여 BufferedReader가 사용하고 있던 시스템 리소스(예: 파일 디스크립터 또는 스트림)를 해제해준다.
이렇게 함으로써 리소스 누수를 방지하고, 프로그램이 깔끔하게 종료될 수 있도록 돕는다. 
파일 입출력 시에는 항상 close() 호출을 잊지 않는 것이 중요한다.
private static boolean isSurprising(String s): 이 메서드는 문자열 s가 '놀라운 문자열'인지 판별하여 true 또는 false를 반환한다. 
private static으로 선언되어 클래스 내부에서만 호출 가능하며 객체 생성 없이 사용된다.
int n = s.length();: 입력 문자열의 길이를 저장한다.
길이 예외 처리 (if(n <= 2)):
문자열 길이가 1인 경우 (예: "X"), D-쌍 자체가 정의될 수 없으므로 항상 놀라운 문자열이다.
문자열 길이가 2인 경우 (예: "EE"), D는 0만 가능하며, 0-쌍은 단 하나만 생성되므로 항상 놀라운 문자열이다.
이러한 짧은 문자열에 대한 빠른 처리는 효율성을 높이다.
외부 루프 (for(int d = 0; d <= n - 2; d++)): D 값 순회
문제에서 정의한 대로, D는 0부터 N-2까지의 모든 가능한 값을 가진다. 
이 루프는 각 D에 대해 검사를 수행한다.
Set<String> dPairs = new HashSet<>();: 각 D마다 새로운 HashSet을 초기화한다.
HashSet은 중복된 요소를 저장할 수 없기 때문에, 여기에 D-쌍을 추가하면서 중복 여부를 효과적으로 검사할 수 있다.
내부 루프 (for(int i = 0; i < n - (d + 1); i++)): D-쌍 생성 및 중복 검사
이 루프는 현재 D 값에 해당하는 모든 D-쌍을 문자열 s에서 추출한다.
i는 D-쌍의 첫 번째 문자의 인덱스이다.
i + d + 1은 D-쌍의 두 번째 문자의 인덱스이다. 
d가 두 문자 사이의 거리를 나타내므로, i와 i + (d + 1) 위치의 문자가 한 쌍을 이룬다.
루프 조건 i < n - (d + 1)은 두 번째 문자의 인덱스(i + d + 1)가 문자열의 범위를 벗어나지 않도록 보장한다.
char char1 = s.charAt(i); char char2 = s.charAt(i + d + 1);: 문자열 s에서 두 문자를 가져온다.
String pair = "" + char1 + char2;: 두 문자를 결합하여 String 형태의 D-쌍을 만든다 (예: "ZG").
if(!dPairs.add(pair)): 생성된 pair를 HashSet에 추가한다. 
add() 메서드는 pair가 성공적으로 추가되면 true를, 이미 dPairs에 동일한 pair가 존재하여 추가되지 못하면 false를 반환한다.
!dPairs.add(pair) 조건은 HashSet에 중복된 pair가 이미 존재했음을 의미한다.
즉, 현재 D에 대해 D-쌍이 중복되었으므로, 이 문자열은 D-유일하지 않다. 
문제 정의상 하나라도 D-유일하지 않으면 '놀라운 문자열'이 아니므로, 즉시 return false;를 실행하여 메서드를 종료한다.
return true;: 모든 D 값에 대한 검사를 통과하여 어떠한 중복된 D-쌍도 발견되지 않았다면, 이 문자열은 '놀라운 문자열'이므로 최종적으로 true를 반환한다.

코드로 구현

package baekjoon.baekjoon_30;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;

// 백준 1972번 문제
public class Main1147 {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line;

        // 입력의 마지막 줄인 '*'이 올 때까지 반복합니다.
        while(!(line = br.readLine()).equals("*")) {
            // isSurprising 메서드를 호출하여 놀라운 문자열인지 확인합니다.
            if(isSurprising(line)) {
                System.out.println(line + " is surprising.");
            } else {
                System.out.println(line + " is NOT surprising.");
            }
        }
        br.close();
    }

    // 주어진 문자열이 놀라운 문자열인지 판별하는 메서드입니다.
    private static boolean isSurprising(String s) {
        int n = s.length();

        // 문자열 길이가 1 이하인 경우 항상 놀라운 문자열입니다.
        // D-쌍이 정의되지 않거나 (N < 2), D-쌍이 단 하나만 존재 (N = 2, D = 0)하여 항상 유일합니다.
        if(n <= 2) {
            return true;
        }

        // D는 0부터 N-2까지 정의됩니다.
        for(int d = 0; d <= n - 2; d++) {
            // 각 D에 대해 D-쌍들을 저장할 HashSet을 생성합니다.
            // HashSet은 중복된 요소를 허용하지 않으므로, 중복 여부 확인에 용이합니다.
            Set<String> dPairs = new HashSet<>();

            // 문자열을 순회하며 D-쌍을 추출합니다.
            // i는 첫 번째 문자의 인덱스이고, i + d + 1은 두 번째 문자의 인덱스입니다.
            // 두 번째 문자의 인덱스가 문자열 범위를 벗어나지 않도록 i < n - (d + 1) 조건을 사용합니다.
            for(int i = 0; i < n - (d + 1); i++) {
                // 현재 D-쌍을 구성하는 두 문자를 추출합니다.
                char char1 = s.charAt(i);
                char char2 = s.charAt(i + d + 1);

                // 두 문자를 조합하여 문자열 쌍을 만듭니다 (예: "ZG").
                String pair = "" + char1 + char2;

                // HashSet에 해당 쌍을 추가합니다.
                // 만약 add 메서드가 false를 반환하면, 이미 같은 쌍이 HashSet에 존재한다는 의미입니다.
                // 이는 D-쌍이 중복되었다는 뜻이므로, 이 문자열은 D-유일하지 않습니다.
                if(!dPairs.add(pair)) {
                    // 중복이 발견되면, 이 문자열은 놀라운 문자열이 아닙니다.
                    return false;
                }
            }
        }

        // 모든 D에 대해 중복된 D-쌍이 발견되지 않았다면, 놀라운 문자열입니다.
        return true;
    }
}

마무리

코드와 설명이 부족할수 있습니다. 코드를 보시고 문제가 있거나 코드 개선이 필요한 부분이 있다면 댓글로 말해주시면 감사한 마음으로 참고해 코드를 수정 하겠습니다.

profile
Junior backend developer

0개의 댓글