개발 이야기/알고리즘 및 코테 준비

Python Counter와 Counter 사용 문제(백준 2108, 최빈값 찾기)

혁진 2023. 1. 24. 10:31

문제 2108 최빈값 찾기

www.acmicpc.net/problem/2108

 

2108번: 통계학

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

www.acmicpc.net

해당 문제 중 최빈값(mode)를 구하는 문제는 python에서는 collection의 Counter를 사용하는 것이 편하다고 한다.

(sort이후에 lst[i]==lst[i+1]로 풀라고하다가 계속 틀려서 counter를 이용했다..ㅎ)

대다수의 python으로 푼 최빈값 구하기 알로리즘에서 counter를 이용했기 때문에 간단히 이에 대해 정리하였다. 

풀이는 바로 아래에 적어놓았다 

풀이 

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

def get_mode(num):
    if(len(num)==1):
        return num[0]
    cnt = Counter(num).most_common()
    #most_conter 내림차순으로 가져옴
    if cnt[0][1] != cnt[1][1]:
        return cnt[0][0]
    else:
        array = []
        for t in cnt:
            if t[1] == cnt[0][1]:
                array.append(t[0])
        return sorted(array)[1]



avg = round((sum(lst)/n))
mid = lst[n//2]
mode = get_mode(lst)
diff = lst[-1] - lst[0]

print(avg)
print(mid)
print(mode)
print(diff)

Counter란?

https://docs.python.org/3/library/collections.html#collections.Counter

 

collections — Container datatypes

Source code: Lib/collections/__init__.py This module implements specialized container datatypes providing alternatives to Python’s general purpose built-in containers, dict, list, set, and tuple.,,...

docs.python.org

데이터의 개수를 셀 때 유용한 collections 모듈의 Counter 클래스가 python에는 존재한다. 

Counter 생성자는 여러형태의 데이터를 인자로 받아 각 원소가 몇번씩 나오는지 저장된 객체를 반환한다. 

from collections import Counter 
Counter(['a','b','c','d','a','a','e','b','e','e','e'])
Counter({'e': 4, 'a': 3, 'b': 2, 'c': 1, 'd': 1})

 

이때 개수가 많은 것 부터 내림차순으로 반환한다

특정 원소의 개수를 얻으려면 다음과 같이 작성하면 된다.

from collections import Counter 
cnt = Counter(['a','b','c','d','a','a','e','b','e','e','e'])
#Counter({'e': 4, 'a': 3, 'b': 2, 'c': 1, 'd': 1})
cnt[0][0] #e
cnt[0][1] #4
cnt[a] #3

.most_common()

개수가 많은 순서(최빈인 순서)부터 k개를 리턴하는 함수로, 매개변수로 값을 넘기지 않으면, 동일하게 내림차순으로 값을 반환한다. 

cnt = Counter(['a','b','c','d','a','a','e','b','e','e','e'])
cnt.most_common()
[('e', 4), ('a', 3), ('b', 2), ('c', 1), ('d', 1)]
cnt.most_common(2)
[('e', 4), ('a', 3)]

 

추가적인 연산과 함수들 

+, - 산술 연산 

cnt1= Counter(['a','b','c','d','a','a','e','b','e','e','e'])
cnt2 = Counter(['a','b','d','d'])
cnt1+cnt2
Counter({'a': 4, 'e': 4, 'b': 3, 'd': 3, 'c': 1})
cnt1-cnt2
Counter({'e': 4, 'a': 2, 'b': 1, 'c': 1})
#음수나 0이 되면 사라짐

subtract(): 음수를 포함해주는 - 연산

cnt1= Counter(['a','b','c','d','a','a','e','b','e','e','e'])
cnt2 = Counter(['a','b','d','d'])
cnt1.subtract(cnt2)
cnt1
Counter({'e': 4, 'a': 2, 'b': 1, 'c': 1, 'd': -1})

&(교집합), 합집합(|)

cnt1= Counter(['a','b','c','d','a','a','e','b','e','e','e'])
cnt2 = Counter(['a','b','d','d'])
cnt1&cnt2
Counter({'a': 1, 'b': 1, 'd': 1})
cnt1|cnt2
Counter({'e': 4, 'a': 3, 'b': 2, 'd': 2, 'c': 1})

elements() :ist로 재변환(카운터 숫자만큼)

cnt1= Counter(['a','b','c','d','a','a','e','b','e','e','e'])
cnt1
Counter({'e': 4, 'a': 3, 'b': 2, 'c': 1, 'd': 1})
cnt1.elements()
<itertools.chain object at 0x000001BD78F54820>
list(cnt1.elements())
['a', 'a', 'a', 'b', 'b', 'c', 'd', 'e', 'e', 'e', 'e']
list(cnt1)
['a', 'b', 'c', 'd', 'e']