[백준] 2108-통계학-Java

screenshot

[백준] 2108-통계학-Java


❓문제

N개의 정수를 입력 받아 아래의 값을 하나씩 출력하라.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이
  • 최빈값이 여러 개 인 경우 최빈값 중 두번째로 작은 값을 출력한다.
  • 정수의 절대값은 4,000을 넘지 않으며 N의 범위는 1 ≤ N ≤ 500,000 이다.

🖊️풀이법

이번 문제는 최빈값을 제외하고는 간단하게 풀 수 있다.
정수이 절대 값이 4,000을 넘지 않기때문에 카운트정렬을 이용하면 보다 빠르게 풀 수 있다.
절대 값 4000을 기준으로 음수범위, 양수범위를 표현해줄 크기가 8001인 int 배열 arr를 초기화 해준다.

  • 산술평균

변수 sum을 선언하여, 정수를 입력 받을 때마다 더하고, 더한 값을 N으로 나눠 출력한다.
단, 출력 시 반올림 하여 출력해야하기 때문에 double형으로 나눈 후 Math.round를 통해 반올림 후 int 타입으로 형 변환을 시켜준다.

  • 중앙값

반복문을 순회하며, arr[i]가 0이 아닐 경우 해당 값을 count에 더해주고 중앙값에 i-4000을 담아준다.
count(N+1)/2 보다 작을 때 까지 순회하고, 만약 (N+1)/2 보다 커지면 if문을 실행시키지 않고 해당 median값을 반환한다.

  • 최빈값

max값을 구하는 로직을 만들어 arr[i]의 배열이 max 인 경우, mode(최빈 값)i-4000로 할당해줌과 동시에 최빈 값이 동일할 경우를 대비해 flagtrue로 변환해 준다.
만약 mode_max의 값이 같고 flagtrue인 경우, 최빈 값을 다시 재지정 후 flagfalse로 변환한다.
최빈값이 여러개인 경우 두번째 작은 수를 반환해야하기 때문

정답 코드

import java.io.*;


public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        int N = Integer.parseInt(br.readLine());
        int[] arr = new int[8001];
        int sum = 0;
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        int median = 0;
        int mode = 0;
        for(int i = 0; i< N; i++){
            int num = Integer.parseInt(br.readLine());
            arr[num+4000]++;
            sum += num;
            if(num > max){
                max = num;
            }
            if(num < min){
                min = num;
            }
        }

        int count = 0;
        int mode_max = 0;
        boolean flag = false;

        for(int i = min + 4000; i<= max+4000; i++){
            if(arr[i] > 0){

                //최빈값 구하기
                if(count < (N+1) /2){
                    count += arr[i];
                    median = i - 4000;
                }

                //최빈값 구하기
                if(mode_max < arr[i]){
                    mode_max = arr[i];
                    mode = i - 4000;
                    flag = true;
                } else if(mode_max == arr[i] && flag){
                    mode = i - 4000;
                    flag = false;
                }
            }
        }

        int average = (int)Math.round((double)sum/N);
        int range = max-min;
        sb.append(average).append('\n')
                .append(median).append('\n')
                .append(mode).append('\n')
                .append(range).append('\n');
        System.out.println(sb);
    }
}


정리

풀이법만 봐서는 이해가 잘 가지않을 수 있기 때문에, 반드시 코드와 함께 보는 것을 권장한다.
이번 문제는 최빈값이 여러개인 경우, 두 번째로 작은 숫자를 출력하는 부분이 핵심인 것 같다.
boolean타입으로 상태표시를 처리해 줌으로써 풀 수 있는 문제였다.