[코딩테스트] 가운데를 말해요 (우선순위 큐)

최지나·2024년 4월 29일
3

코딩테스트

목록 보기
148/154

문제

백준이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 백준이가 정수를 하나씩 외칠때마다 동생은 지금까지 백준이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 백준이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.

예를 들어 백준이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 백준이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 백준이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 백준이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.

출력

한 줄에 하나씩 N줄에 걸쳐 백준이의 동생이 말해야 하는 수를 순서대로 출력한다.

예제 입력 1

7
1
5
2
10
-99
7
5

예제 출력 1

1
1
2
2
2
2
5

생각

  • 매번 정렬 후 중간 값을 찾는 것은 너무 당연하게,, 시간초과가 발생한다. (시간제한:0.1 초)

  • 처음에는 priority queue를 하나 선언한 뒤, 수들의앞의 절반을 stack에 잠시 덜어놓았다가 다시 add하는 방법으로 문제를 풀고자 하였으나 시간초과가 발생하였다

  • 그래서 우선 순위 큐 2개를 사용하였다. 큐는 index 접근이 안되니, 숫자들의 상위 50%와 하위 50%를 각각 담당하는 우선 순위 큐 (최대힙, 최소힙) 2개를 선언하였다

  • 우선순위큐 정의

    1. maxHeap: 숫자들의 하위 50% 담당 최대힙. 정답은 이 maxHeap의 root값에 해당
    2. minHeap: 숫자들의 상위 50% 당당 최소힙
  • 두 힙의 사이즈가 같은 경우 maxHeap에 offer, 다를 경우 minHeap에 offer

  • minHeap과 maxHeap이 각각 숫자들의 상위 절반과 하위 절반을 담고 있어야 하므로 힙이 비어있지 않고, minHeap.peek() < maxHeap.peek() 라는 잘못된 로직이 성립되는 경우 각 heap의 root값을 교체해주어야 한다

  • 항상 maxHeap의 root값을 return

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.PriorityQueue;

public class TellMiddlePart {

    public String tellMiddle(int[] arr) {

        StringBuilder sb = new StringBuilder();
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();

        for (int i = 0; i < arr.length; i++) {
            if (minHeap.size() == maxHeap.size())
                maxHeap.offer(arr[i]);
            else
                minHeap.offer(arr[i]);

            if (!minHeap.isEmpty() && !maxHeap.isEmpty())
                if (minHeap.peek() < maxHeap.peek()) {
                    int tmp = minHeap.poll();
                    minHeap.offer(maxHeap.poll());
                    maxHeap.offer(tmp);
                }

            sb.append(maxHeap.peek() + "\n");
        }
        return sb.toString();

    }

    public static void main(String[] args) throws IOException {

        TellMiddlePart T = new TellMiddlePart();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int N = Integer.parseInt(br.readLine());
        int[] arr = new int[N];
        for (int i = 0; i < N; i++) {
            arr[i] = Integer.parseInt(br.readLine());
        }

        System.out.println(T.tellMiddle(arr));
    }

}

문제 출처

profile
의견 나누는 것을 좋아합니다 ლ(・ヮ・ლ)

1개의 댓글

comment-user-thumbnail
2024년 4월 30일

잘봤습니다!

답글 달기