백준 알고리즘

[백준 알고리즘 4344번] 평균은 넘겠지 :: JAVA[자바]

미믜 2022. 10. 8.
반응형

https://www.acmicpc.net/problem/4344

 

4344번: 평균은 넘겠지

대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다.

www.acmicpc.net

 

 


※문제

 

문제

: 대학생 새내기들의 90%는 자신이 반에서 평균은 넘는다고 생각한다. 당신은 그들에게 슬픈 진실을 알려줘야 한다

 

 

 

입력

 

: 첫째 줄에는 테스트 케이스의 개수 C가 주어진다.

둘째 줄부터 각 테스트 케이스마다 학생의 수 N(1 ≤ N ≤ 1000, N은 정수)이 첫 수로 주어지고, 이어서 N명의 점수가 주어진다. 점수는 0보다 크거나 같고, 100보다 작거나 같은 정수이다.

 

 

 

출력

 

: 각 케이스마다 한 줄씩 평균을 넘는 학생들의 비율을 반올림하여 소수점 셋째 자리까지 출력한다.

 

 

 

 


1회차

 

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        
        //테스트 케이스의 개수
        int a = Integer.parseInt(br.readLine());
        
        for (int i = 0; i < a; i++) {
            StringTokenizer scoreScanner = new StringTokenizer(br.readLine()," ");
            
            //학생 수
            short student = Short.parseShort(scoreScanner.nextToken());
            
            //학생 점수
            int[] studentScore = new int[student];
            
            //평균점수
            int averageScore = 0;
            for (int j = 0; j < studentScore.length; j++) {
                studentScore[j] = Integer.parseInt(scoreScanner.nextToken());
                averageScore += studentScore[j];
            }
            
            //평균점수 구하기 완료
            averageScore = averageScore/student;
            
            //평균점수를 넘은 학생수
            double upStudentNum =0;
            for (int j = 0; j < student; j++) {
                if (studentScore[j]>averageScore){
                    upStudentNum ++;
                }
            }
            StringBuilder sb = new StringBuilder();
            
            //비율 구한 후, 0.000% 형식으로 만들고 출력
            System.out.println(sb.append(String.format("%.3f",Math.round(upStudentNum/student*100000)/1000.0)).append("%"));

    }
    }
}

 

 

진행 방식:
1. 테스트 케이스의 개수만큼 입력
2. 평균점수 구하기
3. 평균점수를 넘는 학생 수 구하기
4. 평균점수를 넘는 학생 수의 비율을 구하기
5. 비율을 0.000% 형식으로 만들기
6. 출력

 

 

1. 테스트 케이스의 개수만큼 입력

 

BufferedReader는 Scanner와 같은 기능이지만 Scanner보다 더 소요시간이 짧으며 String 타입으로 받아지는 특징이 있다.

 

최소한의 소요시간을 위하여 BufferedReader를 사용하여 테스트 케이스의 개수를 입력받고,

입력받은 값을 int타입으로 바꾼 다음 a라는 변수에 넣어주었다. 

 

각 테스트 케이스마다 학생의 수와 n명의 점수를 입력받을 예정이기에 for문을 사용하였다.

 

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int a = Integer.parseInt(br.readLine());
        for (int i = 0; i < a; i++) {
        }

 


2. 평균점수 구하기

 

평균점수 = 학생들의 점수 /학생 수

 

학생 수와 학생들의 점수는 공백을 기준으로 값이 입력되어 있다.

 

[예제 입력]
5

5 50 50 70 80 100
7 100 95 90 80 70 60 50
3 70 90 80
3 70 90 81
9 100 99 98 97 96 95 94 93 91

 

엔터를 기준으로 입력받으면 readLind()을 사용해도 되지만, 공백을 기준으로 입력받을 때 readLind()을 사용하면, 한 줄이 하나의 값으로 입력받아진다.

 

ex) 

x = br.readLine() ;

x = 5 50 50 70 80 100;

 

br.readLine()으로 받아진 공백이 포함된 값을

StringTokenizer를 이용하여 공백을 기준으로 나눠서 값을 전달하게 하였다.


그리고 student라는 변수에 StringTokenizer에서 nextToken()을 이용하여 값을 입력받았다.

StringTokenizer scoreScanner = new StringTokenizer(br.readLine()," ");
//학생 수
short student = Short.parseShort(scoreScanner.nextToken());


학생 수(student) 만큼의 점수가 입력되었다. 이제 학생들의 점수를 입력받을 차례이다.

 

이를 위해 studentScore라는 int타입의 배열과 averageScore라는 int타입의 변수를 선언했다.

studentScore = 학생들의 점수가 모인 배열

averageScore = 학생들의 평균점수

 

for문을 돌려 studentScore라는 배열 안에 학생 수 만큼의 점수를 집어넣게 하였다.

동시에 averageScore 안에 각 학생 점수가 더해지게 하였다.

 

int[] studentScore = new int[student];
int averageScore = 0;
for (int j = 0; j < studentScore.length; j++) {
	studentScore[j] = Integer.parseInt(scoreScanner.nextToken());
	averageScore += studentScore[j];
}


for문이 끝남과 동시에 studentScore에는 학생 점수들이 배열로 들어가고,
averageScore에는 학생들의 점수가 더한 값이 들어간다.

 

averageScore에 학생 수를 나눔으로써 평균점수를 구했다.

averageScore = averageScore/student;





3. 평균점수를 넘는 ' 학생 수 ' 구하기

 

 

구한 평균점수를 학생들의 점수와 비교하며 평균점수를 넘는 학생 수를 구할 것이다.

 

먼저,  평균 점수를 넘는 학생 수를 담을 double 타입의 upStudentNum라는 변수를 선언한다. double 타입으로 선언한 이유는 마지막에 소수점자리까지 출력되게 하기 위함이다.

 

 

이제 평균점수가 넘는 학생이 있을땐 upStudentNum 의 카운트가 증가되도록 만들 것이다.

 

 

double upStudentNum =0;
for (int j = 0; j < student; j++) {
	if (studentScore[j]>averageScore){
		upStudentNum ++;
	}
}



학생들의 점수를 모두 담은 studentScore라는배열의 요소를 평균점수를 담은 averageScore와 비교하여 studentScore가 높을 시 upStudentNum 의 카운트가 증가되도록 만들었다.

for문이 끝나자마자 upStudentNum 에 평균점수를 넘는 학생 수가 담겼다.



4.평균점수를 넘는 학생 수의 비율을 구하기

 



평균점수를 넘는 학생 수의 비율 = 평균점수/학생수*100이다.  이를 코드로 표현하면 아래와 같다.

upStudentNum/student*100



Math.round는 반올림하는 함수이다. 자리 수를 지정할 수는 없고 무조건 첫째자리에서 반올림되기 때문에, 소수점 넷째자리에서 반올림이 되도록 Math.round(비율*1000)/1000.0라고 적었다.

Math.round(upStudentNum/student*100000)/1000.0)




5. 비율을 0.000% 형식으로 만들기


위에서 적은 코드 그대로 출력하면 .0으로 끝나는 수는 첫째자리까지만 출력될 것이다.

 


ex) 40.000 -> 40.0

 

그래서 String.format이라는 함수를 사용해야 한다.

String.format이라는 함수는 문자열의 형식을 지정하는 함수이다.  지정하고 싶은 형식은 숫자, 문자열, 8진수, 시간 등 다양하다. 

String.format("형식 지정",지정하고 싶은 문자열·숫자 등 )

 

String.format("%.3f",Math.round(upStudentNum/student*100000)/1000.0)

 

"%.3f"은 실수형을 소수점 세번째자리까지 지정하는 형식이다. 이렇게 하면 아래와 같이 정상적으로 출력되는 것을 볼 수 있다.


ex) 40.000 -> 40.000

 

 

 

 

6. 출력

 

System.out.println(String.format("%.3f",Math.round(upStudentNum/student*100000)/1000.0)+"%");


위처럼 println으로 + 해서 %를 붙이는 방법 보다  StringBuilder를 선언하고 + 대신 append(비율).append("%")로 하는 것이 시간을 더 단축한다는 걸 깨달았다.

 

StringBuilder sb = new StringBuilder();
System.out.println(sb.append(String.format("%.3f",Math.round(upStudentNum/student*100000)/1000.0))
.append("%"));

 

 

 

 

 

 


2회차

 

변경사항
: 시간 172 -> 180으로 증가..ㅠㅠ

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int a = Integer.parseInt(br.readLine());
        for (int i = 0; i < a; i++) {
            StringTokenizer scoreScanner = new StringTokenizer(br.readLine()," ");
            short student = Short.parseShort(scoreScanner.nextToken());
            int[] studentScore = new int[student];
            int averageScore = 0;
            for (int j = 0; j < studentScore.length; j++) {
                studentScore[j] = Integer.parseInt(scoreScanner.nextToken());
                averageScore += studentScore[j];
            }
            averageScore = averageScore/student;
            double upStudentNum =0;
            for (int j = 0; j < student; j++) {
                if (studentScore[j]>averageScore){
                    upStudentNum ++;
                }
            }
            System.out.printf(String.format("%.3f",Math.round(upStudentNum/student*100000)/1000.0));
            System.out.println("%");

    }
    }
}

 

여러개를 합쳐서 출력 할 때 StringBuilder 대신 System.out.printf 와 System.out.println를 번갈아서 사용했더니 

오히려 시간이 170ms -> 180ms로 늘어났다..

앞으로는 StringBuilder를 열심히 쓰겠습니다..... 

 

 

 

 


3회차

 

변경사항 
: 시간 172 -> 168로 감소!!
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int a = Integer.parseInt(br.readLine());
        StringTokenizer st;
        for (int i = 0; i < a; i++) {
            st = new StringTokenizer(br.readLine()," ");
            int students = Integer.parseInt(st.nextToken());
            int[] Scores = new int[students];
            int averScore = 0;
            for (int j = 0; j < Scores.length; j++) {
                Scores[j] = Integer.parseInt(st.nextToken());
                averScore += Scores[j];
            }
            averScore = averScore/students;
            double upStudentNum =0;
            for (int j = 0; j < students; j++) {
                if (Scores[j]>averScore){
                    upStudentNum ++;
                }
            }
            StringBuilder sb = new StringBuilder();
            System.out.println(sb.append(String.format("%.3f",Math.round(upStudentNum/students*100000)/1000.0)).append("%"));
    }
    }
}

 

StringTokenizer를 for문 밖에서 선언만 했는데도 시간이 줄었다!!

반응형

댓글