본문 바로가기

컴퓨터/백준 알고리즘

백준 알고리즘 2108번: 통계학(자바 Java)

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

 

2108번: 통계학

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

www.acmicpc.net

1. 코드

import java.util.*;

class Main{
	
	static int index;		//배열 인덱스 값
	
	//배열 인덱스 찾기
	public static void arrayIndex(int n) {
		if(n > 0) index = n + 4000;			//입력된 값이 양수라면
		else if(n < 0) index = n * -1;			//음수라면
		else index = 0;					//0이라면
	}
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();				//수의 총 갯수
		int sum = 0;					//입력된 수들의 합
		int big = 0;					//최대 빈도 수
		int[] arr = new int[n];				//수
		int[] count = new int[8002];			//카운팅 정렬
		
		for(int i = 0; i < n; i++) {			//수 입력
			arr[i] = sc.nextInt();
			arrayIndex(arr[i]);			
			count[index]++;
			big = big > count[index] ? big : count[index];	//최대 빈도수 확인
			sum += arr[i];
		}
		
		Arrays.sort(arr);
		int cnt = 0;		//두 번째로 작은 값 확인용 변수
		int num = 4001;		//최빈값
		for(int i = 0; i < n; i++) {
			arrayIndex(arr[i]);
			if(count[index] == big && num != arr[i]) { //최대 빈도수이면서 중복되지 않은 값이라면
				num = arr[i];
				cnt++;
			}
			else continue;
			if(cnt == 2) break;
		}
		
		System.out.println(Math.round((double)sum / n));
		System.out.println(arr[n / 2]);
		System.out.println(num);
		System.out.println(arr[n - 1] - arr[0]);
		sc.close();
	}
}

(실행)

2. 풀이

int[] count = new int[8002];		//카운팅 정렬

계수 정렬을 활용하여 해당 문제를 해결했다. 계수 정렬을 활용하기 위해서는 수의 범위를 알아야하는데 문제에서 입력되는 정수의 절대값은 4000이하라고 한다. 따라서 0을 포함한 -4000~4000의 수를 저장할 공간이 필요하기에 위와 같이 배열을 선언한다.

static int index;		//배열 인덱스 값
	
//배열 인덱스 찾기
public static void arrayIndex(int n) {
	if(n > 0) index = n + 4000;			//입력된 값이 양수라면
	else if(n < 0) index = n * -1;			//음수라면
	else index = 0;					//0이라면
}

arrayIndex 메소드는 계수 정렬을 원활하게 하기 위해 배열의 인덱스 값을 찾아주는 메소드이다. 입력된 수(n)가 양수라면 index 값에 4000을 더하고 음수라면 -1을 곱하고 0이라면 0으로 초기화를 시켜준다.

for(int i = 0; i < n; i++) {		//수 입력
	arr[i] = sc.nextInt();
	arrayIndex(arr[i]);			
	count[index]++;
	big = big > count[index] ? big : count[index];		//최대 빈도수 확인
	sum += arr[i];
}

반복문을 통해서 입력을 받는데 수를 arr배열에 저장한 뒤 해당 인덱스 값에 배열을 1증가 시킴으로써 빈도수를 증가시키는데 최대 빈도수(big)가 바뀌면 해당 빈도수로 저장한다. 그리고 입력된 값에 대한 합계를 sum에 저장해준다.

Arrays.sort(arr);
int cnt = 0;		//두 번째로 작은 값 확인용 변수
int num = 4001;		//최빈값
for(int i = 0; i < n; i++) {
	arrayIndex(arr[i]);
	if(count[index] == big && num != arr[i]) {		//최대 빈도수이면서 중복되지 않은 값이라면
		num = arr[i];
		cnt++;
	}
	else continue;
	if(cnt == 2) break;
}

배열을 오름차순으로 정렬한 뒤 반복문을 통해서 최대 빈도수가 겹치는 경우 최대 빈도수를 가지면서 두 번째로 작은 값으로 최빈값(num)으로 지정한다.

3. 느낀점

사실이 문제는 예전에 풀어서 해결했던 문제인데 2022년 12월 21일 데이터 추가 이후 틀렸기에 다시 풀어보았는데 최빈값에 대한 조건을 제대로 보지 않아서 생각보다 시간이 걸렸다.