
수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.
산술평균 : N개의 수들의 합을 N으로 나눈 값
중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
최빈값 : N개의 수들 중 가장 많이 나타나는 값
범위 : N개의 수들 중 최댓값과 최솟값의 차이
N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.
첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.
첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.
둘째 줄에는 중앙값을 출력한다.
셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.
넷째 줄에는 범위를 출력한다.
해당 문제는 최빈값을 구하는 것 빼고는 쉬운데 최빈값 중 두 번째로 작은 값을 구하는 것이 상당히 시간을 뺏는다.
산술평균은 Math.round()를 사용하여 int형으로 변환 시켜서 출력하면 되고, 중앙값은 입력을 받은 배열의 (n-1) / 2의 인덱스 값을 출력하면 된다. 범위는 arr[n-1] - arr[0] (정렬을 먼저 한 뒤)를 하면된다. 이제 최빈값을 구해보자.
해당 수가 몇번 나왔는지 알려면 Couting Sort를 써야한다는 것을 떠올릴 수 있다. 문제에서 수의 절댓값 범위가 4000을 넘지 않는다고 해서 배열의 크기를 8001로 선언하였다. 이는 저장할 때 +4000을 해주면 되는데, -4000 ~ 4000 범위가 0 ~ 8000으로 바뀌게 할 수 있다.
최대 빈도수를 찾아서 구한 뒤 CountingSort 한 배열에서 최대 빈도수와 같은 것을 찾아주면 되는데 두 번째로 작은 값을 찾아야 하기 때문에 boolean 변수를 사용하였다. 0부터 cnt 길이만큼 1씩 증가 시키면서 maxFreq와 같을 경우 최빈값을 저장하는데 이때 첫번째 최빈값을 만나면 check 를 true 바꾸고 두번째 최빈값을 찾아주면 되는 것이다.
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] arr = new int[n];
int sum = 0;
for (int i = 0; i < n; i++) {
arr[i] = sc.nextInt();
sum += arr[i];
}
Arrays.sort(arr);
// 빈도 수를 구하기 위함
int[] cnt = new int[8001];
for (int i = 0; i < arr.length; i++) {
cnt[arr[i] + 4000] += 1;
}
int maxFreq = 0;
for (int i = 0; i < cnt.length; i++) {
maxFreq = Math.max(cnt[i], maxFreq);
}
// 최빈값
int mode = arr[0];
// 두번째 수인지 판별하는 변수
boolean check = false;
for (int i = 0; i < cnt.length; i++) {
if (cnt[i] == maxFreq) {
if (check) {
mode = i - 4000;
break;
}
mode = i - 4000;
check = true;
}
}
int avg = (int) Math.round((double) sum / n);
int mid = arr[(n - 1) / 2];
int range = arr[n - 1] - arr[0];
System.out.println(avg);
System.out.println(mid);
System.out.println(mode);
System.out.println(range);
}
}