문제 링크

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

문제 설명

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

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

 

Leo는 모든 음식의 스코빌 지수가 K이상이 될 때까지 반복하여 섞습니다.

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

 

제한사항

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

입출력 예

scoville K return
[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회입니다.

문제 풀이

[고려사항]

scoville 배열을 오름차순으로 정렬해서 1번째 원소가 K 이상일때까지 음식을 섞어서 횟수를 구한다.

- 새로운 음식의 스코빌 지수를 만들때마다 scovillle 배열은 오름차순으로 정렬되어야 한다. 

- scoville의 길이는 최대 1,000,000(100만), K는 최대 1,000,000,000(10억)이므로 시간복잡도를 고려해야한다.

 

[알고리즘, 구현방법]

이 문제는 array나 ArrayList로 구현하면 효율성 검증을 통과하지 못한다.  

그래서 최솟값을 빠르게 찾을 수 있는 완전 이진트리 형태의 구조를 가지는 Heap으로 구현해야한다.

 

처음에는 Heap의 삽입, 삭제 연산을 array로 구현해서 제출했는데 시간초과로 실패했다.

*이후에 찾아보니까 이 문제를 Heap으로 직접 구현해서 푸는걸 시도한 사람들도 실패했다고 한다.

그래서 Java에서 Heap구조를 가진 PriorityQueue(우선순위 큐)로 구현했다. 

 

[풀이 과정]

  1. 우선순위 큐를 오름차순으로 생성하여 scovile 값 삽입
  2. Queue의 1,2번째 원소를 가져와서 계산 
    • 섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)
  3. 계산한 값을 Queue에 삽입하고 섞은 횟수 증가
  4. 2,3번 과정을 Queue의 첫번째 원소가 K보다 같거나 클때까지 반복
    • 이때, Queue의 사이즈가 2미만이면 스코빌 지수를 K이상으로 만들수 없다는 뜻이므로 -1 return

[구현시 고려한 사항]

PriorityQueue 함수 호출시 실패하는 경우 Exception을 던지는 함수가 아닌, null이나 false를 반환하는 함수로 구현했다.

  • offer() vs add()
  • poll() vs remove()
  • element() vs peek()

 

정답 코드

import java.util.*;
class Solution {
    // PriorityQueue 사용하여 Heap (Min-Heap) 으로 구현
    public int solution(int[] scoville, int K) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for (int val : scoville) {
            queue.offer(val);
        }

        // 스코빌 지수 계산
        int first, second, mix;
        int count = 0; // 섞은 횟수
        // 루트 값이 K와 같거나 크면 종료
        while (queue.peek() < K) {
            if (queue.size() < 2) {
                return -1;
            } else {
                // 연산할 값 가져오기
                first = queue.poll();
                second = queue.poll();

                // 섞은 음식의 스코빌 지수를 삽입
                mix = first + (second * 2);
                queue.offer(mix);
                count++;
            }
        }
        return count;
    }
}

+ Recent posts