만족은 하되 안주하지는 말자

기록해야 기억한다

프로그래밍/programmers&bj

[C++][알고리즘] 프로그래머스 "더맵게" 문제(heap)

D36choi 2019. 8. 18. 18:28
728x90

https://programmers.co.kr/learn/courses/30/lessons/42626?language=cpp#

 

코딩테스트 연습 - 더 맵게 | 프로그래머스

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다. 섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2) Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다. Leo가 가진

programmers.co.kr

문제 설명

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.

섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)

Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다.
Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.

제한 사항

  • scoville의 길이는 1 이상 1,000,000 이하입니다.
  • K는 0 이상 1,000,000,000 이하입니다.
  • scoville의 원소는 각각 0 이상 1,000,000 이하입니다.
  • 모든 음식의 스코빌 지수를 K 이상으로 만들 수 없는 경우에는 -1을 return 합니다.

입출력 예

scovilleKreturn

[1, 2, 3, 9, 10, 12] 7 2

입출력 예 설명

  1. 스코빌 지수가 1인 음식과 2인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다.
    새로운 음식의 스코빌 지수 = 1 + (2 * 2) = 5
    가진 음식의 스코빌 지수 = [5, 3, 9, 10, 12]

  2. 스코빌 지수가 3인 음식과 5인 음식을 섞으면 음식의 스코빌 지수가 아래와 같이 됩니다.
    새로운 음식의 스코빌 지수 = 3 + (5 * 2) = 13
    가진 음식의 스코빌 지수 = [13, 9, 10, 12]

모든 음식의 스코빌 지수가 7 이상이 되었고 이때 섞은 횟수는 2회입니다.

 

 

머리싸매고 짠 코드, 그러나 실패

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
#include <string>
 
#include <vector>
 
#include <queue>
 
 
 
using namespace std;
 
 
 
int solution(vector<int> scoville, int K) {
 
    priority_queue<intvector<int>, greater<int>> PQ;
 
    int answer = 0;
 
    for (int i = 0; i < scoville.size(); i++) {
 
        PQ.push(scoville[i]);
 
    }
 
    int mix;
 
    int first, second;
 
    if (PQ.top() < K) {
 
        first = PQ.top();
 
        PQ.pop();
 
        second = PQ.top();
 
        PQ.pop();
 
        answer++;
 
        first = first + second * 2;
 
        while (PQ.top() < K || first < K) {
 
            first = first + PQ.top() * 2;
 
            PQ.pop();
 
            answer++;
 
        }
 
    }
 
 
 
    return answer;
 
}
cs

샘플케이스는 통과하였으나....

실제 채점에선 수많은 테스트 케이스에서 시간초과가 나왔다.

우선순위 큐를 이용하는 아이디어에는 문제가 없지만

조건문에서 보다 나은 방법을 찾아야되는듯 싶다.

 

우선순위 큐의 원리를 보다 잘 이해하면 빠르게 결과가 나올 것.

 

성공한 결과물

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
 
#include <string>
 
#include <vector>
 
#include <queue>
 
using namespace std;
 
 
 
int solution(vector<int> scoville, int K) {
 
    priority_queue<intvector<int>, greater<int>> PQ;
 
    int answer = 0;
 
    for (int i = 0; i < scoville.size(); i++) {
 
        PQ.push(scoville[i]);
 
    }
 
    int first, second;
 
    while (PQ.top() < K) {
 
        if (PQ.size() <= 1) {
 
            return -1;
 
        }
 
        first = PQ.top();
 
        PQ.pop();
 
        second = PQ.top();
 
        PQ.pop();
 
        first = first + second * 2;
 
        PQ.push(first);
 
        answer++;
 
    }
 
    return answer;
 
}
cs

if문을 while문으로 바꾸고 쓸데없는 mix 변수를 뺐다.

그 뒤 제출했더니 4~5개 케이스를 제외하고는 모두 예쁘게 성공하였다.

예외인 경우를 생각안했다는 사실을 알고

while문 속 if문을 통해 만약 우선순위 큐에 1개 혹은 0개가 남을 경우 (그럴일은 없는듯 하지만)

-1을 리턴하도록 하였더니 모두 성공..!

문제 포인트

PQ를 이용하여 알아서 value 별로 정렬되도록 하는 것.

greater<> & less<> 를 통한 오름차순 내림차순 우선순위 정렬의 구분

PQ.push를 계속 활용하는 것.

예외 관리