백준 학점계산프로그램

KIMYEONGJUN·2025년 12월 18일
post-thumbnail

문제

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

첫째 줄에 과목별 등급이 나열된 문자열 S가 주어진다.
등급 사이에는 별도의 구분자가 없다.
문자열은 표에 있는 문자들로만 이루어져 있으며, 최대 1000 글자로 이루어져 있다.

문자열 S에 나열된 등급으로 구한 학점의 산술평균을 첫째 줄에 출력한다.
정답과 출력값의 절대/상대 오차는 10^-4까지 허용한다.

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

입력 준비 및 학점 정의
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));:
System.in은 컴퓨터 키보드를 통해 들어오는 원시 데이터(바이트)이다.
InputStreamReader가 이 바이트 데이터를 BufferedReader가 읽을 수 있는 문자로 변환한다.
BufferedReader br는 변환된 문자를 효율적으로 저장하고 한 번에 읽을 수 있도록 버퍼라는 임시 저장 공간을 사용한다. 
이제 br이라는 도구를 사용해서 쉽게 입력을 받을 수 있게 된다.
String input = br.readLine();: br 도구를 이용해 사용자(또는 채점 시스템)가 입력한 한 줄의 등급 문자열(예: "CA+ABBB+A")을 읽어와 input 변수에 저장한다.
double dap = 0;: 총 학점을 저장할 변수 dap입니다. 학점은 4.5처럼 소수점이 있으므로 double 타입(실수)으로 선언하고 0으로 시작한다.
int cnt = 0;: 처리한 과목 수를 저장할 변수 cnt입니다. 정수이며 0으로 시작합니다. 나중에 평균을 낼 때 이 값으로 dap을 나눈다.
HashMap<String, Double> HM = new HashMap<>();:
HM이라는 이름의 HashMap을 만들어서 각 등급 문자에 해당하는 학점을 미리 정의해둔다.
HM.put("A", 4.0); ... HM.put("F", 0.0);는 'A'는 4.0점, 'F'는 0.0점 등 기본 학점을 매핑하는 부분이다.
HM.put("+", 0.5);: '+' 기호를 하나의 독립적인 문자처럼 취급하여 0.5점이라는 값을 부여한다.
이렇게 하면 'A+' 같은 등급이 나올 때 'A' 학점(4.0)에 이 '+' 학점(0.5)을 더해서 4.5점을 쉽게 만들 수 있다.
등급 문자열 분석 및 학점 계산 (반복문)
for(int i = 0; i < input.length(); i++) { ... }: input 문자열에 있는 모든 등급을 하나씩 검사하기 위한 반복문이다.
i는 현재 보고 있는 문자의 위치(인덱스)를 나타낸다.
String grade = String.valueOf(input.charAt(i));:
input.charAt(i)는 input 문자열에서 현재 i번째에 있는 문자를 가져온다. 
예를 들어, "CA+ABBB+A"에서 i가 0이면 'C', i가 1이면 'A', i가 2이면 '+'를 가져온다.
String.valueOf(...)는 이 문자를 HashMap의 키 타입인 String으로 바꿔준다.
이제 grade 변수에는 현재 처리할 등급 문자("C", "A", "+")가 문자열 형태로 들어있다.
dap += HM.get(grade);: HM.get(grade)는 grade 변수에 저장된 등급 문자("C", "A", "+")를 HashMap HM에서 찾아 해당하는 학점 값을 가져온다. 
이 값을 dap (총 학점)에 계속 더해나간다. 
예를 들어, 'C'가 나오면 2.0이 더해지고, 다음 'A'가 나오면 4.0이 더해진다. 
이어서 '+'가 나오면 0.5가 더해진다. 
이 방식으로 'C' + 'A' + '+' = 2.0 + 4.0 + 0.5 = 6.5 와 같이 총점이 계산된다.
if (!grade.equals("+")) { cnt++; }:
이 조건문은 과목 수를 세는 중요한 부분이다. 
'+'는 독립적인 과목이 아니라 앞의 등급에 추가되는 점수일 뿐이다. 
그래서 grade가 "+"가 아닐 때만 (!grade.equals("+")), 즉 'A', 'B', 'C', 'D', 'F'와 같은 실제 등급이 나올 때만 cnt (과목 수)를 1씩 증가시킨다.
이렇게 해야 정확한 과목 수를 셀 수 있다.
평균 학점 계산 및 출력 준비
double average = dap / cnt;: 모든 문자를 처리하고 총 학점 dap과 총 과목 수 cnt가 모두 계산되면, dap을 cnt로 나누어 평균 학점 average를 구한다. 
dap이 double 타입이므로 결과도 소수점까지 정확하게 나온다.
DecimalFormat df = new DecimalFormat("#.#####");:
DecimalFormat 객체 df를 만든다. 
"# .#####"라는 패턴은 "숫자를 출력하되, 소수점 아래는 최대 5자리까지 보여주고, 만약 5자리가 안 되거나 불필요한 0이면 제거해라"는 의미이다.
예시: 4.25000은 4.25로, 3.50000은 3.5로, 3.4285714는 3.42857로 포맷팅된다.
String formattedOutput = df.format(average);: 계산된 average 값을 df가 지정한 형식에 맞춰 문자열로 변환하여 formattedOutput 변수에 저장한다.
최종 결과 출력 및 자원 해제
System.out.println(formattedOutput);: 최종적으로 formattedOutput 변수에 담긴 (포맷팅이 끝난) 문자열을 콘솔에 출력한다. 
println은 출력이 끝난 후 자동으로 줄바꿈을 해준다.
br.close();: 사용한 BufferedReader를 닫아 리소스를 해제한다.

코드로 구현

package baekjoon.baekjoon_31;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.HashMap;

// 백준 29614번 문제
public class Main1240 {
    public static void main(String[] args) throws IOException {
        // 표준 입력(키보드)을 읽기 위한 준비 단계
        // - System.in: 표준 입력 스트림으로, 키보드로부터 바이트 단위의 데이터를 받습니다.
        // - InputStreamReader: 바이트 단위인 System.in을 BufferedReader가 처리할 수 있는 문자 단위로 변환해 줍니다.
        // - BufferedReader: 문자 단위로 데이터를 효율적으로 읽을 수 있도록 버퍼링 기능을 제공합니다.
        //                   한 줄 전체를 읽어오는 readLine() 메서드를 사용하기 위해 주로 사용됩니다.
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        // 입력 문자열 읽기 (등급 데이터)
        // BufferedReader의 readLine() 메서드를 사용하여 사용자가 입력한 한 줄의 문자열(예: "A+AB+B+C")을 읽어와 'input' 변수에 저장합니다.
        String input = br.readLine();

        // 변수 초기화
        double dap = 0; // 'dap'은 총 학점(Total Score)을 저장할 변수입니다. 학점은 소수점을 포함하므로 double 타입을 사용합니다. 초기값은 0입니다.
        int cnt = 0;    // 'cnt'는 처리된 과목의 총 개수(Number of Subjects)를 저장할 변수입니다. 이 값으로 나중에 평균을 계산합니다. 초기값은 0입니다.

        // 등급-학점 매핑을 위한 HashMap 초기화
        // 등급 문자열(예: "A", "B", "+")을 키(key)로, 해당 학점(예: 4.0, 3.0, 0.5)을 값(value)으로 저장하는 HashMap을 생성합니다.
        // 이 HashMap을 활용하여 입력 문자열의 각 문자에 해당하는 학점을 빠르고 쉽게 찾아낼 수 있습니다.
        HashMap<String, Double> HM = new HashMap<>();
        HM.put("A", 4.0); // A 등급의 학점은 4.0점
        HM.put("B", 3.0); // B 등급의 학점은 3.0점
        HM.put("C", 2.0); // C 등급의 학점은 2.0점
        HM.put("D", 1.0); // D 등급의 학점은 1.0점
        HM.put("F", 0.0); // F 등급의 학점은 0.0점
        HM.put("+", 0.5); // '+' 기호는 0.5점을 추가하는 의미로 사용됩니다. 예를 들어, 'A+'는 'A'의 4.0점과 '+'의 0.5점을 합쳐 4.5점이 됩니다.

        // 입력 문자열 순회 및 학점 계산
        // 'input' 문자열의 첫 번째 문자부터 마지막 문자까지 순서대로 반복하면서 각 등급을 처리합니다.
        for (int i = 0; i < input.length(); i++) {
            // 현재 인덱스 'i'에 해당하는 문자를 가져와 String 타입으로 변환합니다.
            // HashMap의 키가 String 타입이므로 String.valueOf()를 사용하여 타입을 맞춰줍니다.
            String grade = String.valueOf(input.charAt(i));

            // HashMap 'HM'에서 현재 'grade'에 해당하는 학점 값을 찾아 'dap' (총 학점)에 더합니다.
            // 예를 들어, 'A'가 나오면 4.0이 더해지고, 바로 다음 '+'가 나오면 0.5가 추가로 더해져 A+가 4.5점으로 계산됩니다.
            dap += HM.get(grade);

            // '+' 문자는 독립적인 과목을 나타내는 것이 아니라, 이전 등급에 대한 부가적인 점수입니다.
            // 따라서, 총 과목 수 'cnt'를 셀 때는 '+'가 아닌 실제 등급 문자('A', 'B', 'C', 'D', 'F')일 때만 1을 더합니다.
            if (!grade.equals("+")) {
                cnt++;
            }
        }

        // 평균 학점 계산
        // 모든 등급 문자를 처리한 후, 계산된 총 학점('dap')을 총 과목 수('cnt')로 나누어 최종 평균 학점을 구합니다.
        // dap이 double 타입이므로, 나눗셈 결과도 double 타입으로 정확하게 계산됩니다.
        double average = dap / cnt;

        // 결과 출력 형식 지정 (DecimalFormat 사용)
        // DecimalFormat 객체를 생성하여 평균 학점의 출력 형식을 지정합니다.
        // "#.#####" 패턴:
        // - '#': 숫자를 나타내며, 의미 없는 선행 0이나 후행 0은 출력하지 않습니다.
        // - '.': 소수점을 나타냅니다.
        // - '#####': 소수점 이하 최대 5자리까지 출력하되, 그 뒤에 불필요한 0(예: 4.25000)은 출력하지 않습니다.
        //            이 패턴을 사용하면 원하시는 "4.25", "3.5", "3.42857"과 같은 형태로 출력이 됩니다.
        DecimalFormat df = new DecimalFormat("#.#####");
        // 계산된 평균 학점('average')을 위에서 정의한 형식에 맞춰 문자열로 변환합니다.
        String formattedOutput = df.format(average);

        // 최종 결과 출력
        // 포맷팅된 문자열 'formattedOutput'을 표준 출력(콘솔)에 출력합니다.
        System.out.println(formattedOutput); // printf(formattedOutput) 대신 println을 사용하면 줄바꿈이 자동으로 포함됩니다.

        // 9. 자원 해제
        // BufferedReader는 시스템 자원을 사용하므로, 모든 작업이 끝난 후에는 반드시 close() 메서드를 호출하여 자원을 반환해야 합니다.
        br.close();
    }
}

마무리

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

profile
Junior backend developer

0개의 댓글