백준 - 통계학[java]

스브코·2021년 12월 2일
0
post-custom-banner

문제 출처: https://www.acmicpc.net/problem/2108

문제 설명

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

산술평균 : N개의 수들의 합을 N으로 나눈 값
중앙값 : N개의 수들을 증가하는 순서로 나열했을 경우 그 중앙에 위치하는 값
최빈값 : N개의 수들 중 가장 많이 나타나는 값
범위 : N개의 수들 중 최댓값과 최솟값의 차이
N개의 수가 주어졌을 때, 네 가지 기본 통계값을 구하는 프로그램을 작성하시오.

예제 입력

5
1
3
8
-2
2

예제 출력

2
2
1
10

문제 풀이

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

public class Main {
    public static void main(String [] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));


        StringBuilder sb = new StringBuilder();
        int total = Integer.parseInt(br.readLine());
        int [] arr = new int[total];
        double avg = 0;
        for(int i = 0; i < total; i++) {
            arr[i] = Integer.parseInt(br.readLine());
            avg += arr[i];
        }
        avg /= total;
        
        //산술평균
        avg = Math.round(avg);
        int av = (int) avg;
        sb.append(av).append("\n");
        Arrays.sort(arr);
        
        //중앙값
        sb.append(arr[total / 2]).append("\n");
        
        // 최빈값 구하기
        int [] frequency = new int [4001];
        int [] negFrequency = new int [4001];
        for(int elem : arr) {
            if(elem < 0)
                negFrequency[Math.abs(elem)]++;
            else
                frequency[elem]++;
        }
        int max = 0;
        int num = 0;
        int second = num;
        for(int i = negFrequency.length - 1; i > 0; i--) {
            if(negFrequency[i] > max){
                max = negFrequency[i];
                num = -i;
                second = num;
            }
        }
        
        for(int i = 0; i < frequency.length; i++) {
            if(frequency[i] > max){
                max = frequency[i];
                num = i;
                second = num;
            }
        }

        int minusEliminatedIndex = num < 0 ? -num : num;
        if(num < 0) {
            for (int i = minusEliminatedIndex - 1; i > 0; i--) {
                if (negFrequency[i] == max) {
                    second = -i;
                    break;
                }
            }
        }

        if(second != num)
            sb.append(second).append("\n");
        else {
            int x = num < 0 ? 0 : num + 1;
            for(int i = x; i < frequency.length; i++) {
                if(frequency[i] == max){
                    second = i;
                    break;
                }
            }
            sb.append(second).append("\n");
        }
		//범위
        sb.append(Math.abs(arr[total - 1] - arr[0])).append("\n");
       System.out.println(sb);
    }
}

평균, 중앙값, 범위 구하는것은 어렵지 않으나 최빈값을 구하는 부분이 좀 생각을 해야하는 문제이다.

내가 구한 방법은

숫자별 빈도를 구하기 위해서 배열을 음수와 양수 용으로 하나씩 만든후 빈도를 기록을한다.

negative Frequency[4001]
positive Frequency[4001]

기록 후 최빈값이 음수이면 중복값을 찾기 위해 음수 빈도 배열을 확인한다.

index를 설정하는게 관건인데 예를 들어 -10이 최빈값이면 negative Frequency 배열의 인덱스 10 부터 1까지를 스캔한다. 이런식으로 음수는 거꾸로 스캔을하고 양수는 오름차순으로 스캔하면 된다.

다른 풀이

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));
		
		StringBuilder sb = new StringBuilder();
		
		int N = Integer.parseInt(br.readLine());
		
		int[] countSort = new int[8001]; // 넣은 숫자들, 최빈값
		int median = 100000; // 중앙값
		int max = Integer.MIN_VALUE; // 최소값
		int min = Integer.MAX_VALUE; // 최대값  범위
		int sum = 0;
		int range = 0;
		int count = 0;
		double avg = 0.0;
		int mode_max = 0;
		int mode_value = 10000;
		boolean flag = false;
		
		for (int i = 0; i < N; i++) {
			int input = Integer.parseInt(br.readLine());
			countSort[input + 4000]++; // 4000이 기준(==0)
			
			sum += input;
			
			if(input > max) {
				max = input;
			}
			
			if(input < min) {
				min = input;
			}
			
		}
		
		// 산술평균
		avg = Math.rint((double)sum / N);
		
		
		for (int i = min + 4000; i <= max + 4000; i++) { // counting sort는 인덱스가 값이니까
			
			if(countSort[i] > 0) {
				// 중앙값
				if(count <(N + 1) / 2) {
					count += countSort[i];
					median = i -4000;
				}
				
				// 최빈값
				// 중복이 없는 경우
				if(countSort[i] > mode_max){
					mode_max = countSort[i]; 
					mode_value = i - 4000;
					flag = true; 
							
				}
				
				// 중복되는 경우 
				else if(mode_max == countSort[i] && flag == true) {
					mode_value = i - 4000;
                    flag = false;
				}
				
				
			}
		}
		
		// 범위
		range = max + min*-1;
		
		sb.append((int)avg).append("\n");
		sb.append(median).append("\n");
		sb.append(mode_value).append("\n");
		sb.append(range).append("\n");
		
		System.out.println(sb);
		
		
	}
}

8000으로 frequency 배열을 정하고 4000을 더한값으로 index를 찾아 내었다. 생각은 했지만 조금 직관적으로 와닿지 않아서 이렇게 안했는데 더 나은 방법인것 같다.

profile
익히는 속도가 까먹는 속도를 추월하는 그날까지...
post-custom-banner

0개의 댓글