문제
https://www.acmicpc.net/problem/2108
개념
수학, 구현
구현 코드(JavaScript)
const fs = require('fs');
const input = fs.readFileSync(0, 'utf-8').trim().split('\n');
const n = +input[0];
const arr = input.slice(1).map((i) => +i);
arr.sort((a, b) => a - b);
// 산술평균
let avg = (arr.reduce((a, c) => a + c, 0) / n).toFixed(0);
console.log(avg == '-0' ? 0 : avg);
// 중앙값
console.log(arr[Math.floor(n / 2)]);
// 최빈값
const map = new Map();
for (let i = 0; i < n; i++) {
// 빈도수 저장
const num = arr[i] + 4000;
if (map.has(num)) {
map.set(num, map.get(num) + 1);
} else {
map.set(num, 1);
}
}
const max = Math.max(...map.values());
const modes = [];
for (let [k, v] of map) {
if (v === max) {
modes.push(k);
}
}
if (modes.length === 1) {
console.log(modes[0] - 4000);
} else {
modes.sort((a, b) => a - b);
console.log(modes[1] - 4000);
}
// 범위
console.log(arr[arr.length - 1] - arr[0]);
코드 설명
문제 개요
백준 2108번 "통계학" 문제는 주어진 숫자 리스트에 대해 다음 네 가지 통계값을 구하는 문제입니다.
- 산술평균: 모든 값의 평균 (소수점 첫째 자리에서 반올림)
- 중앙값: 정렬된 리스트의 가운데 값
- 최빈값: 가장 자주 등장한 값 (단, 최빈값이 여러 개일 경우 두 번째로 작은 값)
- 범위: 최댓값과 최솟값의 차이
이 중 비교적 쉬운 나머지 3개보다는, 최빈값 알고리즘에 집중해보겠습니다!
개인적으로 최빈값이 가장 어려웠기 때문입니다.. 😳
1️⃣ 숫자의 빈도수를 저장하기 위한 Map
사용
먼저 각 숫자의 등장 빈도수를 저장하기 위해 해시맵(Map 객체)을 이용했습니다.
const map = new Map();
for (let i = 0; i < n; i++) {
const num = arr[i] + 4000; // 음수 처리를 위해 4000을 더해줌
if (map.has(num)) {
map.set(num, map.get(num) + 1);
} else {
map.set(num, 1);
}
}
- 왜
+4000
을 하는가?- 문제에서 주어진 숫자의 범위가
-4000 ~ 4000
이기 때문에, 모든 숫자에 4000을 더해 양수화합니다. - 예를 들어
-2
는3998
,0
은4000
,3
은4003
이 됩니다. - 만약 그대로 사용한다면 음수 인덱스가 할당되어 문제가 발생하여 이렇게 진행했습니다 !
- 문제에서 주어진 숫자의 범위가
2️⃣ 최빈값의 최대 빈도 찾기
const max = Math.max(...map.values());
3️⃣ 최빈값 후보 리스트 만들기
최빈값이 여러 개일 수 있으므로, 최빈값과 같은 빈도수를 가진 숫자를 모두 배열에 저장한다.
const modes = [];
for (let [k, v] of map) {
if (v === max) {
modes.push(k);
}
}
map
을 순회하면서, 빈도수가max
인 숫자를modes
배열에 추가합니다.- 이 과정은 최빈값이 2개 이상일때, 두번째로 빈도수가 높은 수를 최빈값으로 지정하기 위해 필요합니다.
4️⃣ 최빈값 출력
if (modes.length === 1) {
console.log(modes[0] - 4000);
} else {
modes.sort((a, b) => a - b); // 정렬
console.log(modes[1] - 4000); // 두 번째로 작은 값 출력
}
최빈값이 하나라면 그대로 출력하고, 여러 개라면 오름차순 정렬 후, 두 번째로 작은 값을 출력합니다.
개선할 점 😂
문제에서 -0은 허용되지 않는대서 0으로 변경했는데, 사실 원인을 모르고 조건문을 통해 단순 하드코딩했습니다.
이 문제에서 산술 평균 계산 시 toFixed(0) 대신 Math.round()을 이용하면 문제를 해결할 수 있다고 합니다.
toFixed(0)와 Math.round의 차이점
toFixed(0)은 반올림한 값을 문자열로 반환하는데, 다음과 같은 경우 -0이 출력됩니다.
console.log((-0.5).toFixed(0)); // '-0'
console.log((0.5).toFixed(0)); // '1'
반면 Math.round()는 숫자로 반환하기 때문에 -0 문제가 발생하지 않습니다.
console.log(Math.round(-0.5)); // 0
console.log(Math.round(0.5)); // 1
소숫점 첫째자리에서 반올림하면 되므로 이럴 때는 round를 사용하면 좋을 것 같습니다.
'PS' 카테고리의 다른 글
[백준] 16562번: 친구비 (JavaScript) (0) | 2025.02.25 |
---|---|
[백준] 1213번: 팰린드롬 만들기 (JavaScript) (0) | 2025.02.22 |
[백준] 7576번: 토마토 (JavaScript) (0) | 2025.02.22 |
[백준] 11053번: 가장 긴 증가하는 부분 수열 (JavaScript) (0) | 2025.02.21 |
[백준] 1062번: 연결 요수의 개수 (JavaScript) (0) | 2025.02.20 |