라떼는말이야
[프로그래머스 lv1] 실패율 (파이썬) 본문
2019 KAKAO BLIND RECRUITMENT 문제입니다.
문제 설명
슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스테이지 차이가 너무 큰 것이 문제였다.
이 문제를 어떻게 할까 고민 한 그녀는 동적으로 게임 시간을 늘려서 난이도를 조절하기로 했다. 역시 슈퍼 개발자라 대부분의 로직은 쉽게 구현했지만, 실패율을 구하는 부분에서 위기에 빠지고 말았다. 오렐리를 위해 실패율을 구하는 코드를 완성하라.
- 실패율은 다음과 같이 정의한다.
- 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수
전체 스테이지의 개수 N, 게임을 이용하는 사용자가 현재 멈춰있는 스테이지의 번호가 담긴 배열 stages가 매개변수로 주어질 때, 실패율이 높은 스테이지부터 내림차순으로 스테이지의 번호가 담겨있는 배열을 return 하도록 solution 함수를 완성하라.
제한사항
- 스테이지의 개수 N은 1 이상 500 이하의 자연수이다.
- stages의 길이는 1 이상 200,000 이하이다.
- stages에는 1 이상 N + 1 이하의 자연수가 담겨있다.
- 각 자연수는 사용자가 현재 도전 중인 스테이지의 번호를 나타낸다.
- 단, N + 1 은 마지막 스테이지(N 번째 스테이지) 까지 클리어 한 사용자를 나타낸다.
- 만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다.
- 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다.
입출력 예
입출력 예 설명
입출력 예 #1
1번 스테이지에는 총 8명의 사용자가 도전했으며, 이 중 1명의 사용자가 아직 클리어하지 못했다. 따라서 1번 스테이지의 실패율은 다음과 같다.
- 1 번 스테이지 실패율 : 1/8
2번 스테이지에는 총 7명의 사용자가 도전했으며, 이 중 3명의 사용자가 아직 클리어하지 못했다. 따라서 2번 스테이지의 실패율은 다음과 같다.
- 2 번 스테이지 실패율 : 3/7
마찬가지로 나머지 스테이지의 실패율은 다음과 같다.
- 3 번 스테이지 실패율 : 2/4
- 4번 스테이지 실패율 : 1/2
- 5번 스테이지 실패율 : 0/1
각 스테이지의 번호를 실패율의 내림차순으로 정렬하면 다음과 같다.
- [3,4,2,1,5]
입출력 예 #2
모든 사용자가 마지막 스테이지에 있으므로 4번 스테이지의 실패율은 1이며 나머지 스테이지의 실패율은 0이다.
- [4,1,2,3]
나의 풀이
def solution(N, stages):
failure = [0] * N
for i in range(1, N + 1):
total = len([x for x in stages if x >= i])
fail = stages.count(i)
if total == 0: break
failure[i - 1] = fail/total
li = []
for i, v in enumerate(failure):
li.append((v, i + 1))
result = sorted(li, key = lambda x : (x[0], -x[1]), reverse=True)
result = [i[1] for i in result]
return result
1단계 문제치고 풀이가 꽤 오래걸린 문제였다.
오래 걸린 이유는 sorted 함수와 lambda 함수에 대해 자세히 몰랐던 이유이다.
우선 실패율을 저장하는 리스트인 failure을 선언하고 0으로 초기화한다.
이후 for 문으로 1 ~ N 까지 순회를 한다. 1단계부터 N단계까지 순회하는 것을 의미한다.
total에는 현재 순회중인 레벨보다 더 높은 사용자의 수를 구하고,
fail에는 현재 순회중인 레벨에 머물고 있는 사용자의 수를 구한다.
total이 0이라면 해당 스테이지까지 도달한 사람이 없는 것이므로 break로 빠져나온다.
total이 0이 아니라면 fail / total 로 실패율을 계산해 failure 리스트에 저장한다.
li 함수에는 실패율과 스테이지를 튜플로 동시에 저장한다. for i, v in enumerate(failure)로 (실패율, 스테이지) 형태로 저장한다.
이제 정렬을 할 건데, sorted 함수의 문법을 자세히 몰라 가장 오래 걸린 부분이다.
참고로 sort()는 원본의 리스트를 정렬하는 것이고, sorted()는 사본을 만드는 것이다. 즉, 메모리의 부담이 있는 경우가 아니라면 sorted()가 더 안전하다.
sorted()의 매개변수로 정렬하고자 하는 리스트인 li를 넣고, key를 지정할 수 있다. key로 지정된 함수의 리턴 값을 기준으로 정렬할 수 있다.
하지만 이 문제의 제한사항 4번만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다
조건 때문에 2가지 기준이 필요하다.
- 실패율이 높은 스테이지부터 내림차순으로 정렬
- 실패율이 같은 경우 스테이지가 작은 것부터 오름차순으로 정렬
이처럼 두가지 조건으로 정렬하는 것을 다중 조건이라고 하며 lambda 함수를 사용한다. (lambda 함수에 대해서는 검색해보길)
여기서 또 막혔던 것은 두 가지 조건을 설정하는 것까지는 했는데, 어떻게 하나의 기준에는 오름차순, 다른 기준에는 내림차순으로 정렬하는가 였다.
열심히 구글링을 한 결과 기준에 '-'를 붙이면 역순으로 정렬된다는 것이다 (오름차순이면 내림차순으로, 내림차순이면 오름차순으로)
기본 정렬 기준은 reverse = True/False 로 설정할 수 있다. 옵션을 따로 주지 않는다면 reverse = False (오름차순)로 동작한다.
이렇게 정렬 후 마지막으로 스테이지만 뽑아내면 되기 때문에 (실패율, 스테이지) 에서 스테이지만 뽑아내려면 1번째 인덱스들만 저장하면 된다.
result = [ i[1] for i in result ]
'알고리즘 > 코딩 테스트' 카테고리의 다른 글
[프로그래머스 lv1] 자연수 뒤집어 배열로 만들기 (파이썬) (0) | 2021.06.22 |
---|---|
[프로그래머스 lv1] 문자열 내림차순으로 배치하기 (파이썬) (0) | 2021.06.22 |
[프로그래머스 lv1] 문자열 다루기 기본 (0) | 2021.06.22 |
[프로그래머스 lv1] 정수 내림차순으로 배치하기 (0) | 2021.06.22 |
[프로그래머스 lv1] 크레인 인형뽑기 게임 (파이썬) (0) | 2021.06.21 |
[프로그래머스 lv2] 짝지어 제거하기 (파이썬) (0) | 2021.06.21 |
[프로그래머스 lv2] 멀쩡한 사각형 (2) | 2021.06.19 |
[프로그래머스 lv1] 로또의 최고 순위와 최저 순위 (파이썬) (0) | 2021.06.19 |