코딩테스트

프로그래머스 - 실패율 (레벨1, swift)

momo_9 2020. 6. 28. 04:20

 

문제출처

programmers.co.kr/learn/courses/30/lessons/42889

 

문제설명 

슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스테이지 차이가 너무 큰 것이 문제였다.

 

이 문제를 어떻게 할까 고민 한 그녀는 동적으로 게임 시간을 늘려서 난이도를 조절하기로 했다. 역시 슈퍼 개발자라 대부분의 로직은 쉽게 구현했지만, 실패율을 구하는 부분에서 위기에 빠지고 말았다. 오렐리를 위해 실패율을 구하는 코드를 완성하라.

  - 실패율은 다음과 같이 정의한다.

  : 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수

전체 스테이지의 개수 N, 게임을 이용하는 사용자가 현재 멈춰있는 스테이지의 번호가 담긴 배열 stages가 매개변수로 주어질 때, 실패율이 높은 스테이지부터 내림차순으로 스테이지의 번호가 담겨있는 배열을 return 하도록 solution 함수를 완성하라.

 

제한사항

    -  스테이지의 개수 N은 1 이상 500 이하의 자연수이다.

    -  stages의 길이는 1 이상 200,000 이하이다.

    -  stages에는 1 이상 N + 1 이하의 자연수가 담겨있다.

    -  각 자연수는 사용자가 현재 도전 중인 스테이지의 번호를 나타낸다.

    -  단, N + 1 은 마지막 스테이지(N 번째 스테이지) 까지 클리어 한 사용자를 나타낸다.

    -  만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다.

    -  스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다.

 

입출력 예

Nstagesresult
5[2, 1, 2, 6, 2, 4, 3, 3][3,4,2,1,5]
4[4,4,4,4,4][4,1,2,3]

 

입출력 예 설명

입출력 예 #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]

 

 

문제풀이

와..지금까지 푼 것중에서 가장 오래걸렸다

6시간 정도 걸린거 같은데 중간에 너무 짜증나서 워킹데드 2편 보고옴...그거 빼면 문제에 매달린 시간은 한 4시간 정도 되려나?

보고나니까 술술은 아니고... 어쨌든 안찾아보고 내가 풀었다ㅋㅋㅋ

코드가 너무 길어서 더 단순하게 풀 수 있는 방법이 있을 듯 한데 일단은 이게 지금 내 한계인듯ㅠㅠ

 

내가 짠 코드의 내용을 간단하게 정리해 보면 아래와 같다.

 

1) 각 스테이지별 유저수 카운트 해서 저장하기

2) 각 스테이지별 실패율 계산해서 저장하기

3) 실패율 높은 순으로 스테이지 저장하기

 

이거 3개만 하면 되는거였는데 1번 2번은 금방 했다 한 15분? 정도 걸린듯.

나머지 모든 시간을 3번 해결하는데 보냈다ㅜㅜ

3번이 어려웠던 이유는 스테이지 번호를 실패율이 높은순으로 출력해야 하는데 실패율이 같은 경우엔 낮은 스테이지부터 출력되도록 해야 했다. 또한, 실패율이 같은 경우가 하나가 아닌 경우가 있을 수 있다는 걸 처음엔 생각 못해서 통과가 안되는 이유를 몰라 엄청 헤매었다. 이거 해결 못하면 85퍼 정도밖에 통과가 안된다.

 

근데 이렇게 써놓고 보니까 엄청 간단한 거 같네? 분하다ㅠㅠㅠㅠ

순서대로 설명해보겠다

 

1) 각 스테이지별 유저수 카운트 해서 저장하기

stages : [2, 1, 2, 6, 2, 4, 3, 3]

요렇게 주어지는 stages에 저장된 값들은 현재 유저들이 멈춰있는 스테이지 번호이다. 따라서 저장된 값들의 갯수(stages.count)가 현재 게임을 하고 있는 유저의 수가 된다. 반복문을 통해 각 스테이지별로 머물고 있는 유저들이 몇 명인지 세어서 따로 배열(countUsers)에 담아주었다. 배열의 index는 스테이지번호(index = 스테이지번호 -1), 그 안의 값은 해당 스테이지에 머물고 있는 유저들의 수이다.

 

var countUser: [Int] = [Int](repeating: 0, count: N+1)

countUser배열은 이런식으로 초기화를 해주었는데 stages배열에 값이 없는 경우에도 기본적으로 0의 값을 갖도록 해서 해당 스테이지를 표현하기 위함이다. count가 N+1인 이유는 모든 스테이지를 완료한 경우의 유저수도 카운트를 해야하기 때문이다.

 

2) 각 스테이지별 실패율 계산해서 저장하기

문제를 보면 실패율은 아래와 같이 정의한다고 한다.

  실패율 = 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수

이를 다시 표현하면 아래와 같다.

 실패율 = 해당 스테이지에 머물고 있는 사용자 수 / (총 사용자 수 - 해당 스테이지까지 도달하지 못한 플레이어의 수)

   -> failureRate = countUser[index] / (stages.count - addUsercount)

addUsercount에는 스테이지 1부터 사용자의 수가 계속해서 더해지도록 했다.

 

또한, 제한사항을 보면 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다. 라고 하는 부분이 나온다. 따라서 이 부분을 위해 아래 조건문을 추가하여 도달한 유저가 하나도 없는 경우와 모두가 통과한 경우, 실패율이 0으로 처리되도록 하였다.

 -> if countUser[i] == 0  

 

3) 실패율 높은 순으로 스테이지 저장하기

2번까지 실행되었다면 현재 failureRate배열에는 스테이지순으로 실패율이 저장되어 있을 것이다. 이제 해당 failureRate배열을 이용해 실패율이 높은 순으로 스테이지 번호를 출력하면 된다. 난 실패율이 높은 순으로 스테이지 번호가 result배열에 저장되도록 하였다. 여기서 주의할 점은 실패율이 같은 경우를 꼭 처리해주어야 한다는 것이다.

일단 반복문은 failureRate.sorted(by: >)를 사용하여 failureRate의 값이 높은 순서로 값이 들어오도록 하였다. 그 값을 이용해 정렬되어있지 않은 failureRate의 index를 찾도록 하였고(failureRate.firstIndex(of: i)) 해당 index가 result에 포함되어 있는 지 체크 되도록 (if result.contains(idx)) 한 후 result에 저장되도록 하였다. 아래에서 자세히 살펴보자.

 

 failureRate = [0.5, 0.25, 0.5, 0.25]

 failureRate.sorted(by: >) = [0.5, 0.5, 0.25, 0.25]

 result = [0, 2, 1, 3]

 

실패율이 위와 같다고 가정해보자. 내림차순으로 정렬되어 반복문으로 실행되는 순서는 두번째 배열과 같을 것이다. 그리고 우리는 result에 저장된 것과 같이 [1]스테이지 번호는 실패율이 높은 순서부터 내림차순으로, [2]실패율이 같은 스테이지번호끼리는 오름차순으로 정렬된 값을 얻고 싶다.

제일 처음으로, 0.5의 index를 failureRate에서 찾아 result배열에 저장할 것이다. 이 때, result에는 0이 저장된다.

두번째 반복문에 0.5가 또 들어오는데 이때 failureRate에서 찾은 index번호는 0이다. 하지만 result에 이미 저장되어 있으므로 또 다른 반복문을 통해 failureRate에서 두번째로 0.5를 값으로 갖는 index인 2를 찾도록 할 것이다. failureRate에서 0.5를 값으로 갖는 것 중에서(failureRate[j] == i) result배열 포함되어 있지 않은 값(!result.contains(j+1))을 찾으면 된다. 아래 주석을 통해 방금 말한 부분을 다시 한번 설명해 놓았다.

 

 

이렇게 저장된 result를 return하면 끝이다!!!!!!

전체 코드는 아래와 같다.

 

 

와 힘들다 이게 레벨1인데 레벨2는 어떻게 풀지...ㅠㅠ