Algorithm/programmers

[c++] 순위 검색

눙구눙 2022. 6. 10. 15:04

2021 KAKAO BLIND RECURITMENT

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

 

코딩테스트 연습 - 순위 검색

["java backend junior pizza 150","python frontend senior chicken 210","python frontend senior chicken 150","cpp backend senior pizza 260","java backend junior chicken 80","python backend senior chicken 50"] ["java and backend and junior and pizza 100","pyt

programmers.co.kr


map과 이분 탐색의 환장적인 콜라보!

  • 나는 어째서인지 조건들을 무조건 분리해서 map에 다 따로 저장하려고 했는데 조건 전체를 하나의 문자열로 해서 key로 저장하는건 생각 못했다.
  • 주어진 조건을 만족할 수 있는 모든 경우의 수를 만들어보는 것도 역시 생각 못했다.

이틀을 고민하다가 결국 해설지를 보고 풀 수 있었다.

 

1. map을 사용한 자료구조

"java backend junior pizza 150"

위와 같은 정보를 가진 지원자는 쿼리 조건에 -가 올 수 있는 것을 고려해서 총 16가지의 조건에 부합하는 사람이다.

이 조건들을 key로 하고 점수를 value로 가지는 map을 만들 수 있다.

이렇게 되면 map에는 "javabackendjuniorpizza"를 key로 가지고 150을 value로 가진 요소가 있을 것이다.

16가지의 key를 만드는 법은 다양한데 나는 조합으로 만들었다.

이 때, 같은 조건을 가진 사람들이 여러 명일 수 있기 때문에 value를 vector<int>로 했다.

 

2. 이분 탐색

지원자의 정보 및 쿼리의 최대 갯수를 고려했을 때, 점수를 브루트포스로 하나씩 비교하면 5만 * 10만 = 50억의 시간이 걸리기 때문에 다른 방법을 써야 한다.

자료의 갯수가 많을 때 가장 적절한 방법은 이분 탐색이다.

이 때, 특정 점수를 가진 사람이 처음으로 나오는 인덱스를 알면 몇 명인지 알 수 있기 때문에 lowerbound를 찾으면 된다.

이분 탐색은 정렬된 자료에서 사용 가능하기 때문에 lowerbound를 찾기 전에 vector를 정렬해야 한다.

 

더보기
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <map>
#include <algorithm>

using namespace std;

map<string, vector<int>> list;

void make_comb(vector<string> splitted, string s, int idx, int depth) {
    if (depth == 4) {
        list[s].push_back(stoi(splitted[4]));
        return;
    }
    make_comb(splitted, s + splitted[idx], idx + 1, depth + 1);
    make_comb(splitted, s + "-", idx + 1, depth + 1);
}

vector<string> split_info(string info) {
    vector<string> splitted;
    stringstream input(info);
    string temp;

    while (getline(input, temp, ' ')) {
        splitted.push_back(temp);
    }

    return splitted;
}

pair<string, int> split_query(string query) {
    string splitted = "";
    stringstream input(query);
    string temp;

    for (int i = 0; i < 7; i++) {
        getline(input, temp, ' ');
        if (temp.compare("and") == 0) continue;
        splitted += temp;
    }
    getline(input, temp, ' ');

    pair<string, int> p;
    p.first = splitted;
    p.second = stoi(temp);

    return p;
}

vector<int> solution(vector<string> infos, vector<string> queries) {
    vector<int> answer;

    for (string info : infos) {
        vector<string> splitted = split_info(info);
        make_comb(splitted, "", 0, 0);
    }

    for (auto l : list) {
        sort(l.second.begin(), l.second.end());
        list[l.first] = l.second;
    }

    for (string query : queries) {
        pair<string, int> p = split_query(query);
        // 해당 조건을 가진 지원자가 없을 때
        if (list.find(p.first) == list.end()) {
            answer.push_back(0);
        }
        // 해당 조건을 가진 지원자가 있을 때
        else {
            vector<int> score = list[p.first];
            int idx = lower_bound(score.begin(), score.end(), p.second) - score.begin();
            // 주어진 점수 이상을 가진 지원자가 있을 때
            if (idx < (int)score.size()) {
                answer.push_back((int)score.size() - idx);
            }
            else {
                answer.push_back(0);
            }
        }
    }

    return answer;
}

int main() {
    vector<string> info = {
        "java backend junior pizza 150",
        "python frontend senior chicken 210",
        "python frontend senior chicken 150",
        "cpp backend senior pizza 260",
        "java backend junior chicken 80",
        "python backend senior chicken 50"
    };

    vector<string> query = {
        "java and backend and junior and pizza 100",
        "python and frontend and senior and chicken 200",
        "cpp and - and senior and pizza 250",
        "- and backend and senior and - 150",
        "- and - and - and chicken 100",
        "- and - and - and - 150"
    };

    vector<int> answer = solution(info, query);
    for (int i : answer)
        cout << i << '\n';
}

 

참고) 만약 효율성 검사를 통과하지 못했다면 쿼리를 분리하는 반복문에서 vector를 정렬하고 있지 않은지 봐야한다.

그렇다면 지원자의 정보로 map을 다 만든 후에 순회하면서 vector를 정렬하면 효율성 테스트도 통과할 수 있다.