[프로그래머스] [1차] 실패율-JAVA

말하는 감자·2022년 7월 4일
0

Programmers Level 1

목록 보기
62/66
post-thumbnail

프로그래머스 Level 1

🔒 실패율

📚 문제 설명

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

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

  • 실패율은 다음과 같이 정의한다.
    • 스테이지에 도달했으나 아직 클리어하지 못한 플레이어의 수 / 스테이지에 도달한 플레이어 수

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


✅ 제한 사항

  • 스테이지의 개수 N은 1 이상 500 이하의 자연수이다.
  • stages의 길이는 1 이상 200,000 이하이다.
  • stages에는 1 이상 N + 1 이하의 자연수가 담겨있다.
    • 각 자연수는 사용자가 현재 도전 중인 스테이지의 번호를 나타낸다.
    • 단, N + 1 은 마지막 스테이지(N 번째 스테이지) 까지 클리어 한 사용자를 나타낸다.
  • 만약 실패율이 같은 스테이지가 있다면 작은 번호의 스테이지가 먼저 오도록 하면 된다.
  • 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0 으로 정의한다.

📖 입출력 예

N stages result
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]

🔨 첫번째 작성 코드

import java.util.*;

class Solution {
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];
        String[] rate = new String[N];
        
        for(int i=1; i<=N; i++) {
            float total = 0;
            float fail = 0;
            
            for(int s : stages) {
                if(s >= i) total++;
                if(s == i) fail++;
            }
            
            if(total == 0) rate[i-1] = "0.0" + Integer.toString(N-i);
            else rate[i-1] = Float.toString(fail / total) + Integer.toString(N-i); 
        }
        
        Arrays.sort(rate, Collections.reverseOrder());
        
        for(int i=0; i<N; i++) {
            answer[i] = N-Integer.parseInt(rate[i].substring(rate[i].length() -1 , rate[i].length()));
        }
        
        return answer;
    }
}

1, 2, 15, 26, 27만 통과하고 나머지는 실패한 코드...

<문자열 내 마음대로 정렬하기>에서 다른 사람의 코드를 참고해서 실패율 뒤에 스테이지 번호를 역순으로 붙힌 후 내림차순으로 정렬한 다음 마지막 스테이지 부분만 추출하는 코드였다.

근데 어디서부터 어떻게 고쳐야할지 감도 안잡히는...

그래서 초기화 했다...
초심으로 돌아가서 하자...😂


🔨 두번째 작성 코드

import java.util.*;

class Solution {
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];
        
        HashMap<Integer, Float> s_rate = new HashMap<Integer, Float>();
        String[] rate = new String[N];
        
        for(int i=1; i<=N; i++) {
            float total = 0;
            float fail = 0;
            float failure = 0;
            
            for(int s : stages) {
                if(s >= i) total++;
                if(s == i) fail++;
            }
            
            if(total != 0) failure = fail/total;  
            
            s_rate.put(i, failure);
            rate[i-1] = Float.toString(failure);
        }
        
        Arrays.sort(rate, Collections.reverseOrder());
        
        int index = 0;
        for(String r : rate) {
            for(int i=1; i<=N; i++) {
                if(Float.parseFloat(r) == s_rate.get(i)) {
                    answer[index] = i;
                    s_rate.replace(i, (float)-1.0);
                    index++;
                    break;
                }
            }
        }
        
        return answer;
    }
}

이번에는 <문자열 내 마음대로 정렬하기>에서 감자가 작성한 코드를 참고해서 다시 풀었다.

map으로 실패율과 스테이지를 같이 저장하여 정렬 후 스테이지를 찾는 방식이였다.

실패가 현저히 줄어들긴 했지만 아직 3, 10, 11, 13, 17, 22, 23, 24가 남은 상태...

테스트 케이스 다 공개해줬으면 좋겠다ㅠ


🗝️ 세번째 작성 코드

import java.util.*;

class Solution {
    public class game {
        int stage;
        double fail;

        public game(int s, double f) {
            this.stage = s;
            this.fail = f;
        }
    }
    
    public int[] solution(int N, int[] stages) {
        int[] answer = new int[N];
        
        List<game> games = new ArrayList<game>();
        
        for(int i=1; i<=N; i++) {
            double total = 0;
            double fail = 0;
            
            for(int s : stages) {
                if(s >= i) total++;
                if(s == i) fail++;
            }
            
            if(total != 0) games.add(new game(i, fail/total));
            else games.add(new game(i, 0));
        }
        
        Collections.sort(games, (g1, g2) -> Double.compare(g2.fail, g1.fail));
        
        for(int i=0; i<N; i++) {
            answer[i] = games.get(i).stage;
        }
        
        return answer;
    }
}

뭔가 하면서도 불안해서 "이것도 안되겠네ㅋ" 하면서 작성한 코드가...

뜻밖의 5점짜리 코드였다...

"이번엔 ArrayList로 해볼까?!" 했는데 감자는 항상 ArrayList에 두개 이상의 필드를 넣을 때 클래스로 호출해왔기에 스테이지와 실패율을 저장하는 game이라는 클래스를 만들었다.

생성자도 만들어주고

이전 코드와 대부분 비슷하다.

각 스테이지별 현재 단계에 머무는 사람의 수(fail)와 스테이지에 도달한 사람의 수(total)을 구한 후 total이 0이라면 실패율을 0으로, 아니라면 실패율을 fail/total로 해준 후 스테이지 번호와 함께 game객체에 넣어 games에 넣어줬다.

대망의 정렬...
이거땜에 오래걸렸다..

처음에는 이 사이트를 보고

Arrays.sort(games, Comparator.comparingDouble(o1 -> o1.fail));

라고 적었는데

이런 오류가 떴다.

Arrays에는 저런 메소드가 없다는 것 같아서
Collection으로 바꿔주니

실패율이 내림차순...

그렇다고 뒤에 Collections.reverseOrder()를 붙혀줘도 오류가 난다.

어떻게 역순으로 정렬할 수 있을까? 고민하다가 이 사이트를 보고 lambda로 내림차순 정렬이 가능하다는 것을 알았다.

 Collections.sort(games, (g1, g2) -> Double.compare(g2.fail, g1.fail));

내림차순 정렬이라서 g1.fail보다 g2.fail을 먼저 써준다.

원래대로 오름차순으로 정렬했다면 (g1, g2)순으로 정렬되었을 요소들을 Comparator를 이용해 g2가 더 커야 참이 되어 내림차순으로 정렬할 수 있다.

Double.class에서 compare(double d1, double d2) 메소드

  • d1 > d2이면 1 반환
  • d2 < d1이면 -1 반환
  • d1 = d2이면 0 반환

그리고games의 요소를 순차적으로 answer에 넣어주면 끝!!

📑 참고 사이트


🤔 느낀 점

그래서 앞의 코드들은 왜 안된 것일까...??
테스트 케이스를 볼 수 있다면 좋겠다ㅠㅠ

profile
나는 말하는 감자다

0개의 댓글