백준 [JAVA] :: 2108번 통계학

smi·2023년 1월 10일
0

BAEKJOON (백준)

목록 보기
18/56

📚 문제 정의

수를 처리하는 것은 통계학에서 상당히 중요한 일이다. 통계학에서 N개의 수를 대표하는 기본 통계값에는 다음과 같은 것들이 있다. 단, N은 홀수라고 가정하자.

  1. 산술평균 : N개의 수들의 합을 N으로 나눈 값
  2. 중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
  3. 최빈값 : N개의 수들 중 가장 많이 나타나는 값
  4. 범위 : N개의 수들 중 최댓값과 최솟값의 차이

N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

📝 입력

첫째 줄에 수의 개수 N(1 ≤ N ≤ 500,000)이 주어진다. 단, N은 홀수이다. 그 다음 N개의 줄에는 정수들이 주어진다. 입력되는 정수의 절댓값은 4,000을 넘지 않는다.

  • 예제 입력 1
3
0
0
-1
  • 예제 입력 2
1
4000
  • 예제 입력 3
5
-1
-2
-3
-1
-2

📝 출력

첫째 줄에는 산술평균을 출력한다. 소수점 이하 첫째 자리에서 반올림한 값을 출력한다.

둘째 줄에는 중앙값을 출력한다.

셋째 줄에는 최빈값을 출력한다. 여러 개 있을 때에는 최빈값 중 두 번째로 작은 값을 출력한다.

넷째 줄에는 범위를 출력한다.

  • 예제 출력 1
0
0
0
1

(0 + 0 + (-1)) / 3 = -0.333333... 이고 이를 첫째 자리에서 반올림하면 0이다. -0으로 출력하면 안된다.

  • 예제 출력 2
4000
4000
4000
0
  • 예제 출력 3
-2
-2
-1
2

💡 코드

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[] arr2 = new int[8001]; // 정수의 절댓값은 4000이 넘지 않기 때문에
        int sum = 0; int second = 0; // 두 번쨰로 작은 값 저장 변수
        int count = 0; int max = 0;

        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
            sum += arr[i];
        }

        Arrays.sort(arr); 

        // 최빈값 구하기
        for (int i = 0; i < n; i++) {
            arr2[arr[i] + 4000]++;
            max = Math.max(max, arr2[arr[i] + 4000]);
        }

        for (int i = 0; i < arr2.length; i++) {
            if (arr2[i] == max) {
                count++;
                second = i - 4000;
            }

            if (count == 2) { // 최빈값이 두 개 이상
                second = i - 4000;
                break;
            }
        }

        System.out.println((int)Math.round((double) sum / (double) n)); // 합
        System.out.println(arr[(arr.length/2)]); // 중앙값
        System.out.println(second);
        System.out.println(arr[n-1]-arr[0]); // 범위
    }
}

→ Arrays.sort() 사용
다른 건 쉽게 풀었는데 최빈값이 문제였음.. 여러 개면 2번째로 작은 수를 출력해야해서 시간이 좀 걸렸다.


참고코드

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int N = in.nextInt();
        int[] arr = new int[8001]; // 입력값의 범위 : -4000 ~ 4000
        int sum = 0;
        int max = Integer.MIN_VALUE; int min = Integer.MAX_VALUE;
        // median 과 mode 는 -4000~4000 을 제외한 수로 초기화
        int median = 10000; // median = 중앙값
        int mode = 10000;   // mode = 최빈값

        for(int i = 0; i < N; i++) {
            int value = in.nextInt();
            sum += value;
            arr[value + 4000]++;

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

        // 순회 
        int count = 0;	      // 중앙값 빈도 누적 수 
        int mode_max = 0; 	  // 최빈값의 최댓값
        boolean flag = false; // 이전의 동일한 최빈값이 1번만 등장했을 경우 true, 아니면 false

        for(int i = min + 4000; i <= max + 4000; i++) {
            if(arr[i] > 0) {
                // 중앙값 : 누적횟수가 전체 전체 길이의 절반에 못 미친다면
                if(count < (N + 1) / 2) {
                    count += arr[i];	// i 값의 빈도수를 count 에 누적
                    median = i - 4000;
                }

                // 최빈값 : 이전 최빈값보다 현재 값의 빈도수가 더 높을 경우
                if(mode_max < arr[i]) {
                    mode_max = arr[i];
                    mode = i - 4000;
                    flag = true;	// 처음이므로 true 로 변경 
                } 
                // 이전 최빈값 최댓값과 동일한 경우면서 한 번만 중복되는 경우 
                else if(mode_max == arr[i] && flag == true) {
                    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);	// 범위 
    }
}

→ 카운팅정렬 사용
아직 구조를 제대로 이해 못함

profile
공부한 거 올려요 :)

0개의 댓글