Programmers Lv. 3 베스트앨범, 15분
그냥 풀면 되는 구현 문제.
- 장르별 재생회수의 순서
- 장르 내부에서 재생회수의 순서
위 2가지에 대해 정렬되어 있어야 하기 때문에 map을 2개 써야 한다. 그냥 뭐.. map에 genre를 key로 넣어 재생회수 합계와 해당 genre에 속한 노래들의 {재생회수, index}를 저장하면 된다.
int len;
struct Info{
int play, index;
};
struct cmp{
// 조건 1. play가 큰 것.
// 조건 2. index가 작은 것.
bool operator()(Info &a, Info &b){
if(a.play == b.play) return a.index > b.index;
return a.play < b.play;
}
};
typedef pair<string, int> psi;
bool cmpMap(psi &a, psi &b){
if(a.second == b.second) return a.first < a.first;
return a.second > b.second;
}
vector<int> solution(vector<string> genres, vector<int> plays) {
len = plays.size();
// 1. 장르별 재생회수
map<string, int> genrePlay; // genrePlay[i] : genre i의 재생 회수
// 2. 장르 내부에서 재생회수
map<string, priority_queue<Info, vector<Info>, cmp>> genrePlayMap; // genrePlayMap[i] : genre i의 plays pa
for(int i = 0; i<len; i++){
string genre = genres[i];
int play = plays[i];
genrePlay[genre] += play;
Info info; info.index = i; info.play = play;
genrePlayMap[genre].push(info);
}
// map value로 정렬
vector<psi> genrePlays(genrePlay.begin(), genrePlay.end());
sort(genrePlays.begin(), genrePlays.end(), cmpMap);
vector<int> answer;
for(psi data : genrePlays){
string genre = data.first;
priority_queue<Info, vector<Info>, cmp> &pq = genrePlayMap[genre];
answer.push_back(pq.top().index); pq.pop();
if(!pq.empty()) answer.push_back(pq.top().index);
}
return answer;
}
시간복잡도
for문이 O(n). map size는 worst case O(n)이므로 insert/pop에 O(nlogn)이 걸린다. 정렬에는 O(nlogn). 총 합계 O(nlogn)이다.
후기
굳이 pq로 안하고 vector로 넣은 다음에 한 번에 정렬했어도 됐을 것 같다.
Programmers Lv. 3, 스티커 모으기(2), 18분
전형적인 DP 문제.
문제를 딱 보면 dp[i]를 i번째 스티커까지 봤을 때 최댓값으로 둘 지, i번째까지 보고 i번째 스티커를 떼었을 때 최댓값이라고 정의할지 고민이 조금 된다. 그러나 후자로 선택하면 뗀다는 정보가 추가적으로 필요하기에 복잡해진다. 전자로 선택하면 된다.
그러면 점화식은 dp[i] = max(dp[i-1], dp[i-2] + sticker[i])가 된다. 후항은 dp[i-2]에서 sticker를 떼든 말든 상관없이 i번째 스티커를 뗄 수 있기 때문이고, 전항은 i-1번째 스티커를 떼었는지 여부는 모르기 때문이다.
또 하나, 유의해야 할 것이 있는데 이 문제는 선형이 아니라 환형이기 때문에 0번째 스티커를 떼는 경우와 0번째 스티커를 떼지 않는 경우를 고려해야 한다. 전자의 경우에는 마지막 스티커를 뗄 수 없고, 후자의 경우는 마지막 스티커를 뗄 수 있으므로 dp 연산을 어디까지 할지 지정만 잘 해주면 된다.
int len;
int solution(vector<int> sticker)
{
len = sticker.size();
if(len <= 2) return *max_element(sticker.begin(), sticker.end());
vector<int> dp(len, 0);
// case 1. 0번째 것 뜯는 경우
dp[0] = sticker[0];
dp[1] = dp[0];
for(int i = 2; i<len-1; i++){
dp[i] = max(dp[i-1], sticker[i] + dp[i-2]);
}
int answer = *max_element(dp.begin(), dp.end());
// case 2. 0번째 것 뜯지 않는 경우
fill(dp.begin(), dp.end(), 0);
dp[0] = 0;
dp[1] = sticker[1];
for(int i = 2; i<len; i++){
dp[i] = max(dp[i-1], sticker[i] + dp[i-2]);
}
answer = max(answer, *max_element(dp.begin(), dp.end()));
return answer;
}
시간복잡도
O(n) 순회를 2번 하므로 O(n)
'PS > PS Log' 카테고리의 다른 글
23.09.23. 풀었던 문제들 (0) | 2023.09.25 |
---|---|
23.09.19. 풀었던 문제들 (0) | 2023.09.19 |
23.09.14. 풀었던 문제들 (0) | 2023.09.14 |
23.09.12. 풀었던 문제들 (0) | 2023.09.12 |
23.09.11. 풀었던 문제들 (1) | 2023.09.11 |