티스토리 뷰

728x90
반응형

https://www.acmicpc.net/problem/2108

 

2108번: 통계학

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

www.acmicpc.net

 

이번 문제는 생각보다 쉽지 않았음 .. 5분컷일 줄 알았는데 오래걸림 ^^ ,,,

그래도 파이썬 공부하려고 잘 못 쓰는 딕셔너리, 메소드 등등을 써보려고 노력해서 알아낸 사실이 꽤 있다.

그리고 Python3는 자꾸 타임리밋 떠서 ㅠㅠ 그냥 pypy3으로 돌려버림 ,, 

 

Python3에서 돌아가는 방법 아래에!!!

 

우선 내 풀이

 

첫번째 코드

import sys

n = int(sys.stdin.readline())
arr = []
idx = {}
#숫자 받아서 arr 리스트에 넣기 
for i in range(n):
    num = int(sys.stdin.readline())
    arr.append(num)
    #idx에 입력받은 숫자가 키로 없으면 해당 숫자를 키로하여 값을 1로 세팅
    if num not in idx:
        idx[num] = 1
    #입력받은 숫자가 idx에 키로 있으면, 하나가 더 들어온 것이므로 값을 1 더해줌
    elif num in idx:
        idx[num]+=1
#갯수 1개일 때를 따로 빼기 
if n==1:
    print(arr[0])
    print(arr[0])
    print(arr[0])
    print(0)
#갯수가 1개 이상이면
else:
    #우선 오름차순 정렬
    arr.sort()
    #산술평균        
    avg = int(round(sum(arr)/n))
    print(avg)
    #중앙값은 오름차순 정렬한 것에서 가운데 값
    mid = arr[int(n/2)]
    print(mid)
    #최빈값
    #sorted 하면 리스트 반환. 원소는 튜플 
    #빈도수 내림차순(큰->작은), 키값 오름차순(작은->큰)
    idx = sorted(idx.items(),key = lambda x:(-x[1],x[0]))

    #만일 최빈값이 두개라면, 1번째 인덱스의 값, 즉 idx[1][0] 출력하기
    #최빈값이 한개라면 0번째 인덱스의 값, 즉 idx[0][0] 출력하기 
    for i in range(1,len(idx)):
        if idx[0][1] == idx[i][1]:
            print(idx[1][0])
            break;
        else:
            print(idx[0][0])
            break;

    
    ran = arr[n-1] - arr[0]
    print(ran)

 

첫번째 풀이에서 최빈값이 여러개인지 체크할 때, 굳이 for문을 쓴 것 같아서 그냥 첫번째와 두번째 값만 남겼다.

(어차피 최빈값 순으로 정렬했고, 그 다음은 값에 대해 오름차순 했으므로)

이게 시간 더 적게 걸릴 줄 알았는데 오히려 더 걸림.. 왜지..

아무튼 두번째 풀이 

 

두번째 코드  

import sys

n = int(sys.stdin.readline())
arr = []
idx = {}
#숫자 받아서 arr 리스트에 넣기 
for i in range(n):
    num = int(sys.stdin.readline())
    arr.append(num)
    #idx에 입력받은 숫자가 키로 없으면 해당 숫자를 키로하여 값을 1로 세팅
    if num not in idx:
        idx[num] = 1
    #입력받은 숫자가 idx에 키로 있으면, 하나가 더 들어온 것이므로 값을 1 더해줌
    elif num in idx:
        idx[num]+=1
#갯수 1개일 때를 따로 빼기 
if n==1:
    print(arr[0])
    print(arr[0])
    print(arr[0])
    print(0)
#갯수가 1개 이상이면
else:
    #우선 오름차순 정렬
    arr.sort()
    #산술평균        
    avg = int(round(sum(arr)/n))
    print(avg)
    #중앙값은 오름차순 정렬한 것에서 가운데 값
    mid = arr[int(n/2)]
    print(mid)
    #최빈값
    #sorted 하면 리스트 반환. 원소는 튜플 
    #빈도수 내림차순(큰->작은), 키값 오름차순(작은->큰)
    idx = sorted(idx.items(),key = lambda x:(-x[1],x[0]))
    
    #idx의 첫번째, 두번째 값만 남겨두기
    #만일 최빈값이 두개라면, 1번째 인덱스의 값, 즉 idx[1][0] 출력하기
    #최빈값이 한개라면 0번째 인덱스의 값, 즉 idx[0][0] 출력하기 
    idx =[idx[0],idx[1]]
    if idx[0][1] == idx[1][1]:
        print(idx[1][0])
    else:
        print(idx[0][0])

    #범위
    ran = arr[n-1] - arr[0]
    print(ran)

 


 

다른 사람 코드 1

import sys
import math

N = int(sys.stdin.readline())
counter = 8001 * [0]
for i in range(N):
    counter[int(sys.stdin.readline()) + 4000] += 1

average = 0
for i, value in enumerate(counter):
    if value != 0:
        average += (i - 4000) * value
average = average / N
if average - math.floor(average) < 0.5:
    average = math.floor(average)
else:
    average = math.floor(average) + 1

temp = 0
for i in range(len(counter)):
    if temp < (N//2 + 1):
        if counter[i] != 0:
            temp += counter[i]
            med = i - 4000
        continue
    break
if N == 1:
    med = counter.index(max(counter)) - 4000

if counter.count(max(counter)) == 1:
    freq = counter.index(max(counter)) - 4000
else:
    res_counter = [i for i, value in enumerate(counter) if value == max(counter)]
    freq = res_counter[1] - 4000

idx = [i for i, value in enumerate(counter) if value != 0]
rang = max(idx) - min(idx)
sys.stdout.write(str(average) + '\n' + str(med) + '\n' + str(freq) + '\n' + str(rang))

1등 코든데 지금은 이해할 뇌 용량이 안됨 ,,ㅋ ㅋ 나중에 봐야지 ..

 

다른 사람 코드 2

import sys
# import math

N = int(sys.stdin.readline().strip())
arr = [int(sys.stdin.readline().strip()) for _ in range(N)]

arr = sorted(arr)
#빈도수 배열
cnt_arr = {}
sum_arr = 0
for i in arr:
	sum_arr += i
	if i in cnt_arr:
		cnt_arr[i] += 1
	else:
		cnt_arr[i] = 1
avr = round(sum_arr / len(arr))
mid = arr[N//2]
rng = max(arr) - min(arr)
#빈도수 배열의 빈도들 중 최대값 구하기
max_cnt = max(cnt_arr.values())
tmp = []
#최빈값들의 key(최빈값에 해당하는 입력받은 숫자)를 tmp에 담기
for i in cnt_arr:
	if max_cnt == cnt_arr[i]:
		tmp.append(i)
#최빈값 배열을 입력받은 숫자에 대해 오름차순 정렬 
tmp = sorted(tmp)
# 최빈값이 1개이상이면, 두번째 값 출력 
if len(tmp) > 1:
	mode = tmp[1]
#최빈값이 1개이면 해당값 출력
else:
	mode = tmp[0]
print(avr)
print(mid)
print(mode)
print(rng)

 

오,, 이분 코드 나랑 비슷한데 더 간단해서 좋다 .. 

나는 처음부터 빈도수 리스트를 빈도수 내림차순, 입력받은 수 오름차순으로 정렬했는데 이분은 그냥 최빈값을 max()로 구하고, 최빈값에 대해서만 오름차순 정렬해서 뽑아냄 ..

 

게다가 이분꺼는 Python3 돌아감

 

그러면 내꺼도 Python3에서 돌아가게 수정해보자 ..

지금 ..

 

악 input()을 sys.stdin.readline()으로 바꾸니까 Python3 통과함 ㅠㅠㅠㅠ 심지어 다름사람코드2 보다 메모리 적게쓰고 시간도 적게 소요된다 .. 머선 일이지 .. 

암튼 이제 이거 써야겠다 ..


꺠달은 점

1) 딕셔너리 공부하기 

https://dojang.io/mod/page/view.php?id=2309 

 

파이썬 코딩 도장: 25.3 딕셔너리 표현식 사용하기

리스트와 마찬가지로 딕셔너리도 for 반복문과 if 조건문을 사용하여 딕셔너리를 생성할 수 있습니다. 다음과 같이 딕셔너리 안에 키와 값, for 반복문을 지정하면 됩니다. {키: 값 for 키, 값 in 딕

dojang.io

2) sys.stdin.readline() 쓰기 

3) arr[1:][1] 은 arr리스트의 1번째에서 마지막까지의 원소들 중 첫번째, 즉 arr[1]임. 

4) 내림차순 정렬하고 싶을 때 reverse = True 해도 되지만, 정렬 기준이 두가지 이상이고 어떤 것에 대해서는 오름차순, 다른 것에 대해서는 내림차순 정렬하고 싶을 떄 내림차순 하고 싶은 기준에 '-'를 붙여주면 내림차순 정렬됨. 

 

 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함