[문제]
문제 설명이 더 헷갈리게 만들어서 예제를 보고 풀었다. 문제는 간단하게 설명해보면 일단 장르와 플레이 횟수가 저장된 벡터가 인자로 주어지는데, 두 벡터의 각 요소는 쌍이다. 무슨 뜻이냐면, 위 예제에서 classic 장르의 어떤 곡의 플레이 횟수가 500, pop 장르의 어떤 곡의 플레이 횟수가 600 이런 식으로 곡의 장르와 플레이 횟수를 두 벡터에 나눠 저장해둔 것이다. 따라서 두 벡터는 크기가 동일하다. 한마디로 위 예제는 클래식 장르 3곡과 pop 장르 2곡이 담긴 리스트다.
여기서 각 장르 내에서 가장 많이 플레이된 두 곡의 인덱스(고유번호)를 차례대로 배열에 담아 반환하는 것이 문제이다. 또한 가장 많이 플레이 된 장르 순으로 저장되어야 한다. 예를 들어 A 장르의 플레이 횟수 합이 100이고 B 장르의 플레이 횟수 합이 200이면 B 장르의 곡부터 저장한다.
[풀이]
우선 내가 설계한 방법은 다음과 같다. 우선 인자로 장르가 담긴 벡터 genres, 플레이 횟수가 담긴 벡터 plays가 주어진다.
- 장르-인덱스(고유번호) 쌍을 벡터에 저장한다. (i.e. ["classic", 0], ["pop", 1], ...)
- 장르-장르별 곡들의 플레이 횟수 합의 key-value쌍을 가지는 해시맵을 만든다. (i.e. ["classic", 1450], ["pop", 3100])
- 2번의 해시맵의 key-value 쌍을 새로운 벡터에 모두 복사한다.
- 3번의 벡터를 value(플레이 횟수의 합)를 기준으로 내림차순 정렬한다. 결과는 ["pop", 3100], ["classic", 1450]
- 1번의 벡터를 plays[value]를 기준으로 내림차순 정렬한다. 즉 플레이 횟수가 높은 순으로 정렬되며, 결과는 ["pop", 4], ["classic", 3], ["pop", 1], ... 처럼 정렬된다.
- 5번의 벡터를 해시맵에 장르-벡터<인덱스> 쌍으로 저장한다. 즉 ["pop", {4, 1}], ["classic", {3, 0, 2}] 와 같이 저장된다.
- 장르의 종류만큼 루프를 돌면서 4번의 벡터에 저장된 장르 순서를 이용하여 6번 해시맵의 value의 0,1번 째 인덱스 값을 결과 벡터에 차례로 추가한다.
설명이 애매해서 이해하기 힘들 수 있는데 간단히 결과만 말하면 다음과 같다.
vec: ["pop", 3100], ["classic", 1450] 처럼 플레이 횟수가 높은 장르순으로 정렬하고,
map: ["pop", {4, 1}], ["classic", {3, 0, 2}] 처럼 장르 내의 곡들의 인덱스를 플레이 횟수가 높은 순으로 정렬하여 위 vec의 장르 순서대로 상위 2개의 인덱스들만 차례로 반환할 벡터에 추가하는 것이다. std::sort 함수가 N*logN의 시간 복잡도를 가지므로 해당 코드는 배열의 크기를 N으로 봤을 때, O(N*logN)의 시간 복잡도를 가진다.
[소스 코드]
#include <string>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
vector<int> solution(vector<string> genres, vector<int> plays)
{
vector<int> answer;
size_t size = genres.size();
vector<std::pair<string, uint32_t>> genreIndex;
unordered_map<string, uint32_t> sum;
genreIndex.reserve(size);
sum.reserve(100); // 장르 종류의 최대 개수
for(size_t i = 0; i != size; ++i)
{
genreIndex.emplace_back(std::pair<string, uint32_t>(genres[i], i));
sum[genres[i]] += plays[i];
}
// map의 장르-플레이 횟수의 합 쌍을 벡터에 복사 후 내림차순 정렬
vector<std::pair<string, uint32_t>> sortedSum;
sortedSum.reserve(sum.size());
for(const auto& mypair : sum)
{
sortedSum.emplace_back(std::pair<string, uint32_t>(mypair.first, mypair.second));
}
std::sort(sortedSum.begin(), sortedSum.end(),
[](const std::pair<string, uint32_t>& a, const std::pair<string, uint32_t>& b) -> bool
{
return a.second > b.second;
});
// 장르 - 인덱스 쌍을 플레이 횟수를 기준으로 내림차순 정렬
// i.e.
// p 4
// c 3
// p 1
// ...
std::sort(genreIndex.begin(), genreIndex.end(),
[&](const std::pair<string, uint32_t>& a, const std::pair<string, uint32_t>& b) -> bool
{
return plays[a.second] > plays[b.second];
});
// genreIndex 벡터를 해시맵에 key-value 쌍으로 저장
// p [4, 1]
// c [3, 0, 2]
unordered_map<string, vector<uint32_t>> sortedGenreIndex;
sortedGenreIndex.reserve(size);
for(const auto& mypair : genreIndex)
{
sortedGenreIndex[mypair.first].push_back(mypair.second);
}
// sortedSum(벡터): 장르-플레이횟수 총합
// sortedGenreIndex(맵): 장르-플레이횟수의 인덱스
answer.reserve(2*sortedSum.size());
for(const auto& mypair : sortedSum)
{
answer.push_back(sortedGenreIndex[mypair.first][0]);
if(sortedGenreIndex[mypair.first].size() > 1)
answer.push_back(sortedGenreIndex[mypair.first][1]);
}
return answer;
}
'Algorithm > 프로그래머스' 카테고리의 다른 글
[Level 2] 큰 수 만들기 (0) | 2021.09.20 |
---|---|
[Level 2] 점프와 순간이동 | C++ (0) | 2020.09.23 |
[Level 2] 위장 - 해시 | C++ (0) | 2020.05.28 |
[Level 2] 소수 찾기 - 완전 탐색 | C++ (0) | 2020.05.26 |
[Level 2] H-Index - 정렬 | C++ (0) | 2020.05.24 |
댓글