포스트

백준 2108. 통계학

통계학

정렬 관련 문제

정렬보다는 구현이 중요한 문제였다

1. 간단 설명


image

4개의 평균을 구해야한다

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

2. 예시


5 1 3 8 -2 2

  1. 산술 평균 : (1 + 3 + 8 + -2 + 2) / 5 = 2.4인데 소수 첫째자리에서 반올림한다 답은 2
  2. 중앙값 : 수를 오름차순으로 정렬시, 중앙에 위치하는 값은 3
  3. 최빈값 : 모두 한번씩 등장하므로 여기서는 두번째로 작은값인 1을 출력
  4. 범위 : 최소값은 -2, 최대값은 8이므로 10의 범위를 가짐

주의사항

  • 산술 평균은 소수점 첫째 자리에서 반올림 할 것
  • N의 값은 홀수이므로, 중앙값은 하나만 존재한다
  • 최빈값이 여러개인 경우, 두번째로 작은 값을 출력할 것
  • 범위는 양수임

특히 예제 4번에서

3 0 0 -1

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

라고 명시되어있다. 부동소수점의 특성을 잘 생각해 볼 것

3. 알고리즘


간단히 생각나는 대로 풀이한 방법

1
2
3
4
5
6
7
8
9
10
11
12
1. N을 입력받고 각 수를 입력받는다
	1-1. 수를 입력받으면서, 최빈값 체크를 위해 각 수가 몇번 나왔는지 기록하면서 저장한다.
2. 배열을 저장한다 (중앙값 계산을 위해)
3. 산술 평균을 구해서 출력한다
	- 저장된 원소의 합을 구해서, N으로 나눠서 출력한다
4. 중앙값을 출력한다
	- 간단히 v[N/2]로 출력 가능
5. 최빈값 구하기
	- 먼저 1-1에서 체크한 배열을 체크하여 가장 많이 나온 수를 확인한다
	- 이후 이 수와 같은 회수 만큼 나온 수가 있는지 체크한 뒤, 두번쨰로 작은 값을 출력한다
6. 범위를 구해서 출력한다
	- v[N-1]에서 v[0]를 빼서 절대값을 취해서 출력한다

4. 소스코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <algorithm>

using namespace std;

#define SIZE 8001
#define OFFSET 4000 // [-4000 : 0] ~ [4000 : 8000]으로 저장

int N;
int freq[SIZE];
vector<int> numbers;

void Input() {
	freopen_s(new FILE*, "input.txt", "r", stdin);
	cin >> N;
	for (int i = 0; i < N; i++) {
		int tmp; cin >> tmp; 
		freq[tmp + OFFSET]++; // 입력값은 -4000 ~ 4000
 		numbers.push_back(tmp);
	}

	sort(numbers.begin(), numbers.end(), less<int>()); // 오름차순 정렬
}

int main() {
	Input();

	// 1. 산술평균
	double mean = round(accumulate(numbers.begin(), numbers.end(), 0) / double(N));
	
	if (mean == 0) // 부동소수점 특성상 음의 0이 나올 경우 절대값으로 음수 부호를 떼준다
		cout << abs(mean) << '\n';
	else
		cout << mean << '\n';

	// 2. 중앙값
	cout << numbers[N / 2] << '\n';

	// 3. 최빈값
	int max_freq = 0;
	vector<int> mode_candidates; 
	for (int i = 0; i < SIZE; i++) {
		if (freq[i] > max_freq) {
			max_freq = freq[i];
			mode_candidates = { i }; // 기존의 값을 버리고 새로운 값으로 업데이트
		}
		else if (freq[i] == max_freq) { // 같은 빈도의 최대값이 등장한 경우 넣음
			mode_candidates.push_back(i);
		}
	}

	// 2개 이상이면 두번째 원소를, 하나면 첫번째 원소를 출력
	int mode = mode_candidates.size() > 1 ? mode_candidates[1] : mode_candidates[0];
	cout << mode - OFFSET << '\n';


	// 4. 범위
	cout << abs(numbers[N - 1] - numbers[0]);

	return 0;
}

간단해 보이지만, 은근 꼼꼼히 신경쓸게 있는 문제였다

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.