
이 문제는 겉만 보면 통계 문제인데, 알고 보면 구현 디테일을 검증하기 위한 문제이다.
N이 최대 50만 개나 되니 구현시 속도에 신경써야 한다.
먼저 산술평균, 중앙값, 최빈값, 범위 네 개를 구해야 하므로 일단 입력을 받는 라인을 작성한다.
1단계: 입력 받기 및 환경 설정
N이 최대 50만개라, 그냥 input() 쓰면 시간 초과 날 수 있다.
그래서 안전하게 sys 모듈 가져와서 입력 속도 빠르게 바꾸는 걸 추천한다.
import sys
input = sys.stdin.readline
N번 반복해서 숫자들을 리스트에 담아야 하므로 리스트 이름은 numbers로 지정해 보겠다.
N = int(input())
nums = [int(input()) for _ in range(N)]
2단계: 중앙값, 최솟값, 최댓값 준비 (정렬)
중앙값이나 범위를 구하려면 일단 숫자들이 순서대로 있어야 편리하다.
정렬하는건 어렵지 않으므로 정렬해두는 게 나중에 디버깅도 편하다.
# 중앙값, 범위 계산을 위해 정렬이 필수야.
nums.sort()
1. 중앙값 (Median)
N은 홀수라고 했으니, 정렬된 리스트에서 딱 중간에 있는 값을 찾으면 된다.
중간 인덱스는 N을 2로 나눈 몫만 구하면 되므로 N // 2로 구현하면 된다.
# N이 홀수이므로, 정렬 후 N/2 인덱스가 중앙값이야.
median = nums[N // 2]
2. 범위 (Range)
범위는 가장 큰 값에서 가장 작은 값을 빼면 된다.
정렬했으니까 제일 작은 건 numbers[0]이고, 제일 큰 건 numbers[-1]로 처리하면 됨
# 정렬했으니, 마지막 값(최댓값) - 첫 번째 값(최솟값)
range_val = nums[-1] - nums[0]
3단계: 산술평균 계산
평균은 모든 숫자를 더한 다음 N으로 나누면 된다.
파이썬의 sum() 함수로 간단하게 구현하자.
여기서 주의할 점은
소수점 첫째 자리에서 반올림 < 이 부분이다. 파이썬의 round 함수룰 사용하면 안 되는게 이 문제의 함정이다
왜냐면 round 함수는 '오사오입 규칙'을 갖기 때문이다. 하필 귀찮게...

오사오입 (Banker's Rounding) 규칙
파이썬의 round() 함수는 소수점 첫째 자리가 5일 경우에만 특수한 규칙을 적용합니다.
- 5 미만: 버림 (일반 반올림과 동일)
- 5 초과: 올림 (일반 반올림과 동일)
- 딱 5일 때: 앞자리가 짝수면 버리고, 홀수면 올립니다. (즉, 결과가 짝수가 되도록 반올림합니다.)
| 값 | 일반적인 반올림 (문제 요구사항) | round() 함수의 결과 (오사오입) |
| 2.5 | 3 | 2 (앞자리 2가 짝수이므로 버림) |
| 3.5 | 4 | 4 (앞자리 3이 홀수이므로 올림) |
| 4.5 | 5 | 4 (앞자리 4가 짝수이므로 버림) |
컴퓨터의 원리 때문에 이렇게 지정되었다지만 코테 푸는 입장에선 번거로운 포인트가 아닐 수 없다,,
그래서 아래와 같이 코드를 입력해야 하는데, 그 이유는 다음과 같다.
total = sum(nums)
avg = total / N
mean = int(avg + 0.5) if avg >= 0 else int(avg - 0.5)
1. 양수 처리시
int(avg + 0.5)
- 원리: 반올림할 때, 0.5를 더한 후 정수 부분만 취하면 된다.
- 예시:
- 3.4의 반올림 : 3.4 + 0.5 = 3.9 = 결과값 : 3 (버림)
- 3.5의 반올림 : 3.5 + 0.5 = 4.0 = 결과값 : 4 (올림)
- 3.6의 반올림 : 3.6 + 0.5 = 4.1 = 결과값 : 4 (올림)
2. 음수 처리시
int(avg - 0.5)
- 원리: 음수를 반올림할 때 0.5를 빼준 후 정수 부분만 취해야 한다.
- 예시:
- -3.4의 반올림 : -3.4 - 0.5 = -3.9 = 결과값 : -3
- -3.5의 반올림 : -3.5 - 0.5 = -4.0 = 결과값 : -4
- -3.6의 반올림 : -3.6 - 0.5 = -4.1 = 결과값 : -4
4단계: 최빈값 계산 (가장 까다로운 부분)
가장 많이 나오는 숫자를 찾아야 하는데, N이 50만 개라서 하나하나 세면 속도가 느려질 수 있다.
문제에서 '입력되는 정수의 절댓값은 4,000을 넘지 않는다.'라고 했으므로. 이걸 활용해야 한다.
일단 collections의 Counter 없이 딕셔너리를 써서 빈도수를 계산해보자.
딕셔너리(freq)를 만들어고, get(x, 0) + 1 을 이용해 세면 깔끔하게 셀 수 있다.
freq = {}
for x in nums:
# 딕셔너리에 x가 없으면 0을 반환받아 1을 더하고, 있으면 기존 값에 1을 더함.
freq[x] = freq.get(x, 0) + 1
이렇게 만들어진 딕셔너리에서 가장 큰 값이 몇인지만 찾아서 변수에 넣어주면 된다.
max_cnt = max(freq.values())
만들어진 freq 딕셔너리에서 max_cnt로 나온 값을 기준으로 '두 번째로 작은 값'을 찾으면 된다.
# 최대 빈도수를 가진 숫자들만 모아서 오름차순 정렬
cands = sorted([k for k, v in freq.items() if v == max_cnt])
이때 최빈값이 여러 개면 두 번째로 작은 값인 cands[1]을 뽑고, 아니면 그냥 cands[0]이 정답이 된다.
# 최빈값이 여러 개(cands 길이가 1 초과)면 두 번째 값(인덱스 1), 아니면 첫 번째 값(인덱스 0) 선택
mode = cands[1] if len(cands) > 1 else cands[0]
5단계: 최종 출력
이대로 출력만 하면 된다.
print(avg)
print(median)
print(mode)
print(range_val)
최종 코드
import sys
input = sys.stdin.readline
N = int(input())
nums = [int(input()) for _ in range(N)]
nums.sort()
# 1. 산술평균 (반올림: half-up 방식)
total = sum(nums)
avg = total / N
mean = int(avg + 0.5) if avg >= 0 else int(avg - 0.5)
# 2. 중앙값
median = nums[N // 2]
# 3. 최빈값
freq = {}
for x in nums:
freq[x] = freq.get(x, 0) + 1
max_cnt = max(freq.values())
cands = sorted([k for k, v in freq.items() if v == max_cnt])
mode = cands[1] if len(cands) > 1 else cands[0]
# 4. 범위
range_val = nums[-1] - nums[0]
print(mean)
print(median)
print(mode)
print(range_val)
'IT > CodingTest' 카테고리의 다른 글
| [programmers] '겹치는 선분의 길이' 문제 해설 및 정답코드 (2) | 2025.04.29 |
|---|---|
| [programmers] '등수 매기기' 문제 해설 및 정답코드 (0) | 2025.03.27 |
| [programmers] 'OX퀴즈' 문제를 가장 간단하게 푸는 방법 (0) | 2025.03.27 |
| [programmers] '영어가 싫어요' 문제 해설 및 정답코드 (0) | 2025.03.25 |
| [programmers] '삼각형의 완성조건(2)' 문제 해설 및 정답코드 (0) | 2025.03.25 |
| [programmers] '공 던지기' 문제 해설 및 정답코드 (0) | 2025.03.20 |
| [programmers] '2차원으로 만들기' 문제해설 (0) | 2025.03.18 |
| [programmers] '주사위의 개수' 문제해설 (1) | 2025.03.17 |
댓글