본문 바로가기

자료구조 & 알고리즘 & cs/CodingTest

[python] 백준 2108번 - 통계학

2108번: 통계학 (acmicpc.net)

 

2108번: 통계학

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

www.acmicpc.net

 

정렬 알고리즘 학습 후 위 문제를 풀었는데 

그 중 최빈값을 구하는 알고리즘을 정리하려고 한다.

 

산술평균, 중앙값, 범위의 경우 이제까지 공부한 내용으로 무리없이 작성하였으나

최빈값을 구하는 과정에서 조금 고민했다.

 

파이썬에서 최빈값을 구하기 위해서는

collection 모듈의 Counter 클래스를 사용해야한다.

Counter 클래스는 dic 클래스의 하위클래스로 리스트나 튜플에서 데이터의 등장 횟수를 사전형식으로 반환한다.

Counter 클래스의 most_common() 메소드는 각 데이터가 등장한 횟수를 내림차순으로 정리하여 튜플로 반환한다.

 

예를 들어

(4,5)를 반환하였을 경우 첫번째 요소는 리스트의 원소이고 두번째 요소는 리스트에서 이 원소가 등장한 횟수이다.

정리하자면 리스트에서 원소 4가 총 5번 등장하였다는 말과 같다.

 이를 활용하여 최빈값을 구하는 함수를 만들었다.

 

from collections import Counter

def modeFinder(lst):
    c = Counter(lst)
    order = c.most_common()
    maxn=order[0][0]		#리스트의 최빈값

 

그러나 이 문제에서 주의해야할 점은 리스트에 같은 원소가 중복해서 들어간다는 것이다.

그렇다면 만약 동일한 최빈값이 존재한다면 어떻게 하면 될까?

다음과 같이 함수를 만들어보았다.

 

def modeFinder(lst):
    c = Counter(lst)
    order = c.most_common()
    maxn=order[0][1]
    
    modes=[]
    for num in order:
        if num[1] == maxn:
            modes.append(num[0])
    
    if len(modes)>1:
        modes2=split(modes)
        return modes2[1]
    else:
        return order[0][0]

maxn은 최빈값이 얼마나 등장했는지 그 횟수를 저장한 변수로 사용하였다.

동일한 최빈값이 있는지 확인하기 위해

for문을 이용하여 만약 같은 횟수로 등장한 수가 있다면 modes 리스트에 append한다.

 

만약 modes의 길이가 1보다 크다면 최빈값이 여러개가 되기 때문에 문제에서의 조건을 만족하기 위한 값을 리턴하였고

그 외의 경우 최빈값은 하나만 존재하기 때문에 order[0][0]을 리턴한다.

 

따라서 전체 작성한 함수는 다음과 같다.

import sys
from collections import Counter
lst=[]
n = int(sys.stdin.readline())
for _ in range(n):
    lst.append(int(sys.stdin.readline()))
    

#병합정렬 함수
def split(data):
    if len(data)<=1:
        return data
    medium = int(len(data) / 2)
    left = split(data[:medium])
    right = split(data[medium:])
    return merge(left, right)

def merge(left,right):
    merged=[]
    l_point, r_point = 0,0
    
    while len(left) > l_point and len(right) > r_point:
        if left[l_point] > right[r_point]:
            merged.append(right[r_point])
            r_point += 1
        else:
            merged.append(left[l_point])
            l_point += 1

    # case2 - left 데이터가 없을 때
    while len(left) > l_point:
        merged.append(left[l_point])
        l_point += 1
        
    # case3 - right 데이터가 없을 때
    while len(right) > r_point:
        merged.append(right[r_point])
        r_point += 1
    
    return merged

#최빈값 함수
def modeFinder(lst):
    c = Counter(lst)
    order = c.most_common()
    maxn=order[0][1]
    
    modes=[]
    for num in order:
        if num[1] == maxn:
            modes.append(num[0])
    
    if len(modes)>1:
        modes2=split(modes)
        return modes2[1]
    else:
        return order[0][0]
            


sorted_list = split(lst)

print(round(sum(lst) / n))
print(sorted_list[len(lst)//2])
print(modeFinder(lst))
print(sorted_list[-1]-sorted_list[0])

 

728x90