본문 바로가기
Computer Science/Algorithm

[백준] 2108 - 통계학 (Java)

by soro.k 2022. 9. 22.

https://st-lab.tistory.com/108?category=857114 

 

[백준] 2108번 : 통계학 - JAVA [자바]

www.acmicpc.net/problem/2108 2108번: 통계학 첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다. www.acmicpc.net..

st-lab.tistory.com

*해당 포스팅은 상단에 링크된 포스팅을 바탕으로 개인 공부 목적을 위해 작성되었으므로 자세한 내용은 위 링크를 확인해 주시기 바랍니다.


 

여기서도 그냥 Arrays.sort()를 썼었는데 역시나 선생님은 시간 복잡도를 고려해서 카운팅 정렬을 쓰셨다. O(n)과 O(nlogn)은 천지차이라는 선생님의 말씀을 새겨들어야지. 나는 이 문제에서 최빈값이 되게 어려웠는데 이해가 잘 안 가서 손으로 다시 코드도 쓰고 값이 어떻게 변하는지 표로 그려보니까 조금씩 이해가 갔다. 그리고 max값이랑 min값 구하는 게 다시 한번 정리가 되서 좋았다.

 

아예 입력값을 받으면서부터 합계도 더하고 정렬도 하고 심지어 최댓값 최솟값까지 정리를 해놨다. max를 Integer.MAX_VALUE로 하고 min을 Integer.MIN_VALUE로 해서 입력값이 max보다 크면 max값을 갱신하고 입력값이 min보다 작으면 min값을 갱신하는 게 신박했다. 이런 건 학교에서 배우는 건가..? 나는 아직 배울 게 참 많구나. 중앙값은 배열의 크기에서 1을 더한 값에 2를 나눈 게 배열의 해당 인덱스 값보다 클 때까지 반복을 하면서 구하는데 정말 간결해서 좋았다.

 

예를 들어 1, 3, 8, -2, 2가 입력되면 배열 중에 해당하는 숫자의 인덱스 값이 다 1로 오른다.

count는 0에서 시작이 되고 (N + 1) / 2 = 6 가 될 때까지 반복한다.

 

count median
1 -2
2 1
3 2

 

이렇게 중앙값 2를 구할 수 있다.

 

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        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 = 10000;
        int mode = 10000;

        for(int i = 0; i < N; i++) {
            int value = Integer.parseInt(br.readLine());
            sum += value;
            arr[value + 4000]++;

            if(max < value) {
                max = value;
            }
            if(min > value) {
                min = value;
            }
        }

        int count = 0; // 중앙값 빈도 누적 수
        int mode_max = 0; // 최빈값의 최댓값

        // 이전의 동일한 최빈값이 1번만 등장했을 경우 true, 아니면 False
        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;
            }
        }
        System.out.println((int)Math.round((double)sum / N)); // 산술평균
        System.out.println(median);
        System.out.println(mode);
        System.out.println(max - min);
    }
}

 

산술평균 출력의 경우에는 sum과 N 둘중에 하나는 double형으로 캐스팅 해줘야 소수점을 버리지 않을 수 있고 거기서 반올림을 해준 후에 int형으로 캐스팅해야 한다고 한다!