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

 

코딩테스트 연습 - 실패율 | 프로그래머스

실패율 슈퍼 게임 개발자 오렐리는 큰 고민에 빠졌다. 그녀가 만든 프랜즈 오천성이 대성공을 거뒀지만, 요즘 신규 사용자의 수가 급감한 것이다. 원인은 신규 사용자와 기존 사용자 사이에 스테이지 차이가 너무 큰 것이 문제였다. 이 문제를 어떻게 할까 고민 한 그녀는 동적으로 게임 시간을 늘려서 난이도를 조절하기로 했다. 역시 슈퍼 개발자라 대부분의 로직은 쉽게 구현했지만, 실패율을 구하는 부분에서 위기에 빠지고 말았다. 오렐리를 위해 실패율을 구하는 코드를

programmers.co.kr

게임의 실패율을 구하고 실패율이 높은 스테이지 번호를 순서대로 출력하는 문제이다.

실패율이 같다면 스테이지 번호가 작은 순으로 출력한다.

 

실패율은 다음과 같은 식으로 구한다.

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

 

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

 

나는 먼저 주어지는 stages벡터를 정렬해주었다.

문제에서 주어진 첫 번째 예제(위의 표)를 예로 들어보면 stages를 정렬해줬을 때

1, 2, 2, 2, 3, 3, 4, 6 이 될 것이다.

그러면 스테이지 수만큼 for문을 돌면서 스테이지 번호와 현재 도전 중이 스테이지 번호가 같은 애들 사용자들에 대해서 순차적으로 처리해줄 수 있기 때문이다.

 

즉, i번째 스테이지 일 때, stages의 값이 i인 사용자들(해당 스테이지에 도전 중인 사용자, 클리어하지 못한 사용자)의 수를 스테이지에 도달한 플레이어 수로 나눠주면 된다. 그리고 현재 스테이지에 도전 중인 사용자들은 다음 스테이지에는 도달하지 못하므로 도전중인 사용자수에서 빼준다. 그리고 실패율을 해당 스테이지의 번호와 함께 벡터에 넣어준다.

 

여기서 실수할 수 있는 부분은 문제에서 스테이지에 도달한 유저가 없는 경우 해당 스테이지의 실패율은 0으로 정의한다라는 문제의 조건

을 잘 처리해주어야 한다. i번째 스테이지에 도전 중인 사용자나 클리어한 사용자가 모두 없다면 실패율은 0이 될 것이고 i번 이후의 스테이지들의 실패율도 모두 0이 될 것이다.

 

 

각 스테이지의 실패율을 모두 구했으면 정렬해주어야 한다.

실패율은 내림차순으로 그 실패율이 같다면 스테이지 번호를 오름차순으로 정렬해주기 위해서 비교 함수를 따로 구현(comp)하였다.

정렬이 끝났다면 정렬된 벡터의 두 번째 값(스테이지 번호)을 answer 벡터에 추가한다.  

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <string>
#include <vector>
#include <algorithm>
 
using namespace std;
 
bool comp(const pair<double,int> &a, const pair<doubleint> &b) {
    //실패율 먼저 비교(내림차순)
    if(a.first > b.first) {
        return true;
    } else if(a.first == b.first) {
        //실패율이 같다면 스테이지 번호를 비교(오름차순)
        if(a.second < b.second) {
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}
 
 
vector<int> solution(int N, vector<int> stages) {
    vector<int> answer;
    vector<pair<double,int> > failrate;
    
    sort(stages.begin(),stages.end());
    
    //도전중인 사용자 수
    int usernum = stages.size();
    int index = 0;
    
    for(int i=1; i<=N; i++) {
        
        //i번째 스테이지에 도달한 유저가 없는 경우 실패율은 0
        if(usernum == 0) {
            failrate.push_back(make_pair(0, i));
            continue;
        }
        
        
        int failcnt = 0;
        //i번 stage에 도달했지만 클리어하지 못한 사용자수
        while(stages[index] == i) {
            failcnt += 1;
            index++;
        }
 
        
        double rate = (double) failcnt/usernum;
        failrate.push_back(make_pair(rate, i));
        
        //i번째까지만 도달한 사용사들의 수를 빼준다.
        usernum -= failcnt;
    }
    
    //문제 조건에 맞게 정렬(실패율 내림차순, 스테이지번호 오름차순)
    sort(failrate.begin(),failrate.end(),comp);
    
    //정답에 실패율이 높은 스테이지의 인덱스를 추가한다.
    for(int i=0; i<N; i++) {
        answer.push_back(failrate[i].second);
    }
    
    
    return answer;
}
Colored by Color Scripter
 

https://programmers.co.kr/learn/courses/30/lessons/42888

 

코딩테스트 연습 - 오픈채팅방 | 프로그래머스

오픈채팅방 카카오톡 오픈채팅방에서는 친구가 아닌 사람들과 대화를 할 수 있는데, 본래 닉네임이 아닌 가상의 닉네임을 사용하여 채팅방에 들어갈 수 있다. 신입사원인 김크루는 카카오톡 오픈 채팅방을 개설한 사람을 위해, 다양한 사람들이 들어오고, 나가는 것을 지켜볼 수 있는 관리자창을 만들기로 했다. 채팅방에 누군가 들어오면 다음 메시지가 출력된다. [닉네임]님이 들어왔습니다. 채팅방에서 누군가 나가면 다음 메시지가 출력된다. [닉네임]님이 나갔습니다. 채팅

programmers.co.kr

이 문제는 map을 사용하여서 풀 수 있다. 각 유저 아이디를 key값으로 닉네임을 value로 map에 저장하면 된다.

나중에 닉네임을 바꾸거나 나갔다가 새로 들어올 때, 새로운 닉네임으로 적용돼야 하므로 해당 유저 아이디에 대한 닉네임을 바꿔줘야 한다. 즉, map에 이미 유저 아이디가 이미 존재하는 경우에는 새로운 닉네임(value)으로 바꿔버리면 된다.

 

 

사실 c++을 사용하다 보니까 map이 문제가 아니고 문자열 처리가 귀찮았다...

먼저 각 record에서 유저 아이디와 닉네임을 구분하기 위해서 공백을 기준으로 잘라줘야 한다.

C++에서 이 부분을 처리하려면 다른 방법도 있지만 char 배열과 strtok함수를 사용하면 된다.

strtok 함수는 csting을 include 해주면 된다.

 

 

1. 먼저 string을 char배열로 바꾼 후에

2. char 배열을 공백을 기준으로 잘라주고

3. 다시 string 2차원 배열에 넣어준다.

 

 

string 2차원 배열은 arr[100000][3]으로 선언해놨다. 100000은 문제에서 주어지는 record의 최대 길이이다.

 

arr[index][0] 은 index번째 record의 Enter/Change/Leave 중 하나의 값을 가지고

arr[index][1] 은 index번째 record의 유저 아이디

arr[index][2] 는 index번째 record의 닉네임을 가지도록 저장하였다.

 

모든 record에 대해서 공백을 기준으로 자르고 다시 새로운 string 배열에 넣어줬다면

각 record의 첫 번째 문자열이 Enter이냐 Leave이냐에 따라서 처리해주면 된다(Change일 때는 메시지가 안 뜨므로 처리해줄 필요 없다)

저장해둔 map을 이용하여 Enter인 경우에는 map[key]값과 함께 "님이 들어왔습니다"를 출력해주면 되고

Leave인 경우에는 map[key]값과 함께 "님이 나갔습니다"를 출력해주면 된다.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <string>
#include <vector>
#include <cstring>
#include <map>
 
using namespace std;
 
string arr[100000][3];
 
vector<string> solution(vector<string> record) {
    vector<string> answer;
    
    char str_buff[30];
    map<stringstring> m;
    
    int index = 0;
    for(string r : record) {
        //string을 char array로 바꿔준다.
        strcpy(str_buff, r.c_str());
        int cnt = 0;
        
        //공백을 기준으로 자른다.
        char *tok = strtok(str_buff, " ");
        while (tok != nullptr) {
            //다시 string 배열에 넣어준다. 
            arr[index][cnt++= string(tok);
            
            //다시 공백을 기준으로 자른다.
            tok = strtok(nullptr, " ");
        }
        
        
        //새로 들어오거나 이름을 변경한 경우에만 map에 추가 및 수정
        if(arr[index][0== "Enter" || arr[index][0== "Change") {
            if(m.find(arr[index][1]) == m.end()) {
                //map에 유저아이디가 없다면 새로 추가해준다.
                m.insert(make_pair(arr[index][1],arr[index][2]));
            } else {
                //map에 유저아이디가 이미 있으면 새로운 닉네임으로 바꿔준다.
                m[arr[index][1]] = arr[index][2];
            }
        }
        
        index++;
    }
    
    
    int size = record.size();
    for(int i=0; i<size; i++) {
        if(arr[i][0== "Enter") {
            answer.push_back(m[arr[i][1]] + "님이 들어왔습니다.");
        } else if(arr[i][0== "Leave") {
            answer.push_back(m[arr[i][1]] + "님이 나갔습니다.");
        }
    }
    
    
    
    return answer;
}
Colored by Color Scripter
 

+ Recent posts