자료구조 & 알고리즘/Programmers

[ 프로그래머스 ] 더 맵게 (java)

쉽코기 2022. 5. 4. 16:17

문제

매운 것을 좋아하는 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 합니다.

접근

처음에는 최소 값 두개를 추출하고 조합하여 추가한뒤 다시 정렬을 함으로써

순서를 보장하는 방식을 취했다.

그러나 프로그래머스의 효율성 테스트를 통과하지 못했고

다른 풀이들을 보면서 효율성을 따져보았다.

 

public int solution(int[] scoville, int K) {
        if(K == 0) return 0;

        int count = 0;
        // 정렬이 반드시 필요한 상황이다.
        PriorityQueue<Integer> list = new PriorityQueue<Integer>();
        for(int i : scoville){
            list.add(i);
        }
        Collections.sort(list);

        while(list.size() > 1){
            count ++;
            int mixed = list.get(0) + list.get(1)*2;
            list.remove(0);
            list.remove(0);
            list.add(0 , mixed);
            Collections.sort(list);
            if(list.get(0) >= K){
                break;
            }
        }
        if(list.get(0) >= K){
            return count;
        }else{
            return -1;
        }
    }

 

java 에서의 sort 는 고급 정렬로서 O(n log n) 의 시간 복잡도를 갖는다. while 문 안에 있기에 최종적으로는 O( n^2 * log n ) 을 가지게 된다.

 

그러나 해당 정렬을 매번 사용하지 않고 최소힙을 이용하면 고급 정렬의 시간 복잡도 대신 힙의 추가 삭제 시간 복잡도인 log n 을 사용할 수 있기에 최종적으로 O(n log n) 의 시간 복잡도로 줄어들 수 있다. 힙 정렬 또한 다른 고급 정렬과 마찬가지로 O(n log n)의 시간복잡도를 갖지만 위 구현에서는 힙정렬이 아닌 추가 삭제만 반복해서 일어나는 상황이기때문에 추가 삭제 시간복잡도 O( log n )을 적용 할 수 있었다.

 

힙(priorityQueue)을 이용한 구현은 아래와 같다.

 

import java.util.ArrayList;
import java.util.Arrays;
import java.util.*;

class Solution {
    
    public int solution(int[] scoville, int K) {
    if(K == 0) return 0;
        
    int count = 0;        

    PriorityQueue<Integer> heap = new PriorityQueue<Integer>();
    for(int i : scoville){
        heap.add(i);
    }
        
    while(heap.size() > 1){
        count ++;
        int first = heap.poll();
        int second = heap.poll();         
        int mixed = first + second*2;
        heap.add( mixed);
        if(heap.peek() >= K){
            break;
        }
    }
        if(heap.peek() >= K){
            return count;
        }else{
            return -1;
        }
}
    public void printList(ArrayList<Integer> list ){
        for(int a : list){
            System.out.println(a);
        }
          System.out.println();
    }
    
}

 

 

참고로  자바에서 최대힙은 다음과 같이 구현한다.

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(Collections.reverseOrder());