일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- factory
- synchronized
- spring security
- nestjs
- Volatile
- 일급 컬렉션
- java
- builder
- 일급 객체
- OAuth 2.0
- lombok
- Google OAuth
- middleware
- Spring
- Dependency Injection
- Today
- Total
HJW's IT Blog
[프로그래머스/C++] 순위 검색 본문
https://school.programmers.co.kr/learn/courses/30/lessons/72412
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
문제 분석
주어진 문제는 채용 지원자들의 정보를 바탕으로, 특정 조건을 만족하는 지원자가 몇 명인지 찾는 문제입니다. 지원자 정보는 info 배열로 주어지며, query 배열은 각 개발팀이 궁금한 조건을 포함합니다. 각 info 항목은 "개발언어 직군 경력 소울푸드 점수"의 형식으로 구성되고, 각 query 항목은 "개발언어 and 직군 and 경력 and 소울푸드 점수" 형식입니다.
각 query에 대해 조건을 만족하는 지원자가 몇 명인지 찾아야 합니다.
접근법
- 데이터 분해 및 저장: 각 지원자의 정보를 파싱하고, 이를 저장하는 방식이 필요합니다. 다양한 조건이 있을 수 있으므로, 각 조건을 쉽게 탐색할 수 있는 자료구조를 사용하는 것이 효율적입니다.
- 비트마스킹: 각 정보에 대한 조건을 조합하는 방법으로 비트마스킹을 사용하여 가능한 모든 조합을 미리 계산해두고, 나중에 query를 빠르게 처리할 수 있습니다.
- 이진 탐색을 통한 최적화: 점수에 대한 조건이 주어졌을 때, 조건을 만족하는 점수만을 빠르게 찾기 위해 이진 탐색을 사용합니다. 각 조합에 대해 미리 점수를 정렬해둔 후, lower_bound 함수를 사용하여 빠르게 점수를 찾을 수 있습니다.
#include <bits/stdc++.h>
using namespace std;
vector<string> data_parse(string data){
vector<string> ret;
string tmp = "";
for(auto d : data){
if(d == ' '){
if(tmp != "and") ret.push_back(tmp); // 'and'는 무시
tmp = "";
} else {
tmp += d;
}
}
ret.push_back(tmp); // 마지막 단어 추가
return ret;
}
vector<int> solution(vector<string> info, vector<string> query) {
vector<int> answer;
unordered_map<string, vector<int>> m;
// info 데이터를 조합하여 저장
for(auto data : info){
vector<string> key = data_parse(data); // 데이터를 파싱
int num = stoi(key[4]); // 점수 추출
// 비트마스크로 가능한 모든 조합 생성 (16개)
for(int i = 0; i < 16; i++){
string tmp = "";
for(int j = 0; j < 4; j++){
if(i & (1 << j)){ // 비트가 1이면 해당 조건 선택
tmp += key[j];
} else { // 비트가 0이면 선택하지 않음
tmp += "-";
}
}
m[tmp].push_back(num); // 해당 조합에 점수 저장
}
}
// 각 조합의 점수를 정렬
for(auto& it : m){
std::sort(it.second.begin(), it.second.end());
}
// query 처리
for(auto q : query){
vector<string> key = data_parse(q); // query 파싱
string s = key[0] + key[1] + key[2] + key[3]; // 조건 조합
int num = stoi(key[4]); // 점수 추출
// 이진 탐색으로 조건을 만족하는 점수 개수 찾기
int cnt = m[s].end() - lower_bound(m[s].begin(), m[s].end(), num);
answer.push_back(cnt);
}
return answer;
}
비트 마스킹 원리
for(int i = 0; i < 16; i++)는 비트마스크를 사용하여 4개의 조건(개발언어, 직군, 경력, 소울푸드)에 대해 가능한 모든 조합을 탐색하는 부분입니다. 각 조건은 선택하거나 선택하지 않을 수 있기 때문에, 총 16개의 경우의 수가 생깁니다. 이는 4개의 이진수 자리(2^4 = 16)로 표현될 수 있습니다.
총 4가지의 조건이 있으며, 각 조건마다 선택한다 (1) , 하지 않는다(0) 의 상태를 가집니다,
즉, 2^4 = 16 가지의 조합이 가능합니다.
예를 들어 0000 은 어느 조건도 선택하지 않는경우, 1111 은 모든 조건을 선택하는 경우 입니다.
for(int i = 0; i < 16; i++){
string tmp = "";
for(int j = 0; j < 4; j++){
if(i & (1 << j)){ // 비트가 1이면 해당 조건 선택
tmp += key[j];
} else { // 비트가 0이면 선택하지 않음
tmp += "-";
}
}
m[tmp].push_back(num); // 해당 조합에 점수 저장
}
위 코드에서 i & (1 << j) 를 통해 i 의 j 번째 비트가 1인지 확인 후, 1이라면 key 에 저장된 j 값, 0 이라면 - 를 저장합니다.
예시: i가 0부터 15까지 변하는 과정
i (10진수) i (2진수) 선택 여부 (i & (1 << j))
0 | 0000 | 모든 조건을 선택하지 않음 |
1 | 0001 | 첫 번째 조건만 선택 |
2 | 0010 | 두 번째 조건만 선택 |
3 | 0011 | 첫 번째, 두 번째 조건 선택 |
4 | 0100 | 세 번째 조건만 선택 |
5 | 0101 | 첫 번째, 세 번째 조건 선택 |
6 | 0110 | 두 번째, 세 번째 조건 선택 |
7 | 0111 | 첫 번째, 두 번째, 세 번째 조건 선택 |
... | ... | ... |
15 | 1111 | 모든 조건 선택 |
'Algorithm' 카테고리의 다른 글
[프로그래머스/C++][PCCP 기출문제] 2번 / 퍼즐 게임 챌린지 (0) | 2024.09.12 |
---|---|
[프로그래머스/C++] 퍼즐 조각 채우기 (2) | 2024.09.11 |
[프로그래머스/C++] 괄호 회전하기 (0) | 2024.09.10 |
[프로그래머스/C++] 거리두기 확인하기 (0) | 2024.09.10 |
[프로그레머스/C++] 양궁대회 (1) | 2024.09.06 |