백준 4344번 자바
https://www.acmicpc.net/problem/4344
내용을 바로 보고싶으면 아래 더보기를 눌리면 된다.
알고리즘
첫째 줄에 테스트 케이스 개수 C가 주어진다.
둘째 줄부터 학생의 수 N이 주어지고, N명의 점수가 이어서 주어진다.
1 ≤ N ≤ 1000, N은 정수이고, 0 ≤ 점수 ≤ 100 이다.
1. 학생점수를 넣을 배열 arr, 점수의 합 sum, 평균을 넘은 학생 수 count를 만든다.
2. 테스트 케이스의 개수 C 입력받는다.
3. C만큼 반복한다.
3-1. sum과 count를 0으로 초기화한다.
3-2. 테스트 케이스 한 줄 입력받아 StringTokenizer로 글을 공백기준으로 나눈다.
3-3. 학생의 수 N을 입력받는다.
3-4. N만큼 arr 배열의 길이를 초기화한다.
3-5. N만큼 반복한다.
1) arr에 학생의 점수를 넣는다.
2) sum에 학생의 점수를 더한다.
3-6. 다시 N만큼 반복한다.
1) 만약 평균( sum / N )보다 학생의 점수가 높으면 count를 1+한다.
3-7. 소수점 셋째 자리까지 평균을 넘은 학생 비율( count / N )을 출력한다.
풀이1
import java.io.*;
import java.util.StringTokenizer;
public class No_4344 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int[] arr;
int sum, count;
int C = Integer.parseInt(br.readLine());
for (int i = 0; i < C; i++) {
sum = 0;
count = 0;
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
arr = new int[N];
for (int j = 0; j < N; j++) {
arr[j] = Integer.parseInt(st.nextToken());
sum += arr[j];
}
for (int j = 0; j < N; j++) {
if ((float) sum / N < arr[j]) count++;
}
System.out.printf("%.3f%%\n", ((float) count / N) * 100);
}
}
}
알고리즘대로 풀었다.
학생들의 점수 평균을 구해서 평균을 넘는 학생을 구해야하기에 학생들의 값이 필요했다.
그래서 arr[] 에다가 값을 넣어 저장해둔 것인데 다른 방법은 생각나지 않는다.
소수점을 구해야하기에 실수인 float 또는 double을 써야하는데 그러면 int에 비해 메모리를 더 잡아먹으니까 int로 생성하고 실수가 필요한 계산에는 float로 강제형변환하여 풀었다.
반올림하여 나타내는 방식은 크게 3가지로 다음과 같다.
- printf
- String.format
- Math.round
여기서는 printf에서 사용한 문자들의 뜻은 다음과 같다.
%.3f 는 소수점 3째자리까지 실수를 출력하겠다는 뜻이다.
%% 는 특수문자 %를 나타내기위해 두번 쓰였다.
\n 는 한 줄 띄어쓰기이다.
풀이2
Math.round 메서드로 반올림하여 풀려고 했는데 소수점 아래 0은 전부 삭제한다는 문제가 있었다.
그래서 이 방법은 쓸 수 없을거 같았는데 생각해보면 정수로 반올림을 해버리기때문에 소수점을 가지고있으려면 그만큼 곱한다음 정수로 만들고 그 후 다시 나눠야하는데 너무 복잡한것 같다.
후에 어떻게든 써보려고 했는데 예제는 다 맞췄는데 채점시 틀렸다고 나와서 어디가 문제인지 찾는중이다.
코드는 아래와 같다.
이렇게 하루를 풀어보았는데 못풀어서 내가 자주보는 블로거님에게 문의드렸더니
1
4 1 0 0 0
을 입력하면 25.0%가 나온다고 말해주셔서 바로 고쳐서 풀었다...!
코드는 아래와 같다.
import java.io.*;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int[] arr;
int sum, count;
// 테스트케이스 개수 C
int C = Integer.parseInt(br.readLine());
for (int i = 0; i < C; i++) {
// 각 점수를 더할 sum과 평균을 넘는 학생의 수 count를 0으로 초기화한다.
sum = 0;
count = 0;
st = new StringTokenizer(br.readLine());
// 학생의 수 N
int N = Integer.parseInt(st.nextToken());
// 학생의 수만큼 배열을 만든다.
arr = new int[N];
// 학생의 점수를 배열에 넣은 후 sum에 더한다.
for (int j = 0; j < N; j++) {
arr[j] = Integer.parseInt(st.nextToken());
sum += arr[j];
}
// 평균값 average
float average = (float) sum / N;
// 평균보다 높은 점수를 가진 학생의 수를 센다.
for (int j = 0; j < N; j++) {
if (average < arr[j]) count++;
}
// 평균을 넘는 학생들의 비율을 반올림한 number
double number = Math.round((float) count / N * 100000);
// number의 나머지가 0.0인지 아닌지 확인한다.
if (number % 10 == 0.0) {
// 0.0이면 소수점 3째자리까지 표현해야하므로 String.format으로 다시 비율을 구한다.
System.out.println(String.format("%.3f%%", (float) count / N * 100));
} else {
// 나머지가 0.0이 아니라면 number에다가 %를 붙여서 끝낸다.
System.out.println((number/1000) + "%");
}
}
}
}
풀이3
import java.io.*;
import java.util.StringTokenizer;
public class No_4344 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
int[] arr;
int sum, count;
int C = Integer.parseInt(br.readLine());
for (int i = 0; i < C; i++) {
sum = 0;
count = 0;
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
arr = new int[N];
for (int j = 0; j < N; j++) {
arr[j] = Integer.parseInt(st.nextToken());
sum += arr[j];
}
for (int j = 0; j < N; j++) {
if ((float) sum / N < arr[j]) count++;
}
System.out.println(String.format("%.3f%%", (float) count / N * 100));
}
}
}
이번에는 String.format으로 문자형식을 지정해 출력하였다.
printf랑 비슷한 느낌이지만 이거는 나중에 원하는 소수점으로 계산을 해야할 때 String.format으로 값을 지정하면 좋을것 같다. 이 문제에서는 쓸 일이 없기에 printf로 하면 편할듯하다.
풀이4
import java.io.*;
import java.util.StringTokenizer;
public class No_4344 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
int[] arr;
int sum, count;
int C = Integer.parseInt(br.readLine());
for (int i = 0; i < C; i++) {
sum = 0;
count = 0;
st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
arr = new int[N];
for (int j = 0; j < N; j++) {
arr[j] = Integer.parseInt(st.nextToken());
sum += arr[j];
}
for (int j = 0; j < N; j++) {
if ((float) sum / N < arr[j]) count++;
}
bw.write(String.format("%.3f%%\n", (float) count / N * 100));
}
bw.flush();
}
}
출력을 BufferedWriter로 바꿔보았는데도 성능은 비슷하다.
성능을 더 뽑아내려면 메서드를 만들어야하는 걸까?
테스트케이스가 많고, 메서드가 엄청 반복된다면 빠르게 JIT 컴파일하여서 좀 더 성능을 내지 않을까? 라고 생각해본다.
그렇다면 메서드는 함수(테스트케이스) 이렇게 보내버려서 그 메서드 안에서 처리를 하게 만들어봐야겠다.
메서드를 만들어보았는데 성능은 똑같았다.
참고
'코딩테스트 > Java - 백준' 카테고리의 다른 글
[백준] 4673번 - Java(자바) (0) | 2022.02.04 |
---|---|
[백준] 15596번 - Java(자바) (0) | 2022.02.03 |
[백준] 8958번 - Java(자바) (0) | 2022.01.28 |
[백준] 1546번 - Java(자바) (0) | 2022.01.27 |
[백준] 3052번 - Java(자바) (0) | 2022.01.25 |