개발 공부 기록

[BaekJoon 11286번 / JAVA] 절댓값 힙 본문

PS/Priority Queue

[BaekJoon 11286번 / JAVA] 절댓값 힙

나만없서고냥이 2023. 11. 17. 22:26

Question

https://www.acmicpc.net/problem/11286

 

11286번: 절댓값 힙

첫째 줄에 연산의 개수 N(1≤N≤100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 0이 아니라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0

www.acmicpc.net

 


💡 Solution

일반 큐와 달리 우선순위 큐는 기본적으로 오름차순 정렬입니다. 따라서 오름차순 정렬이 필요할 때는 아래와 같이 기본적으로 선언하면 됩니다.

PriorityQueue<Integer> pq = new PriorityQueue<>();

 

우선순위 큐를 내림차순 정렬하려면 아래와 같이 선언하면 됩니다.

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

 

이번 문제에서는 절댓값을 기준으로 정렬을 해야 하므로, Comparator의 compare 메서드를 오버라이딩하여 절댓값을 기준으로 정렬할 수 있게끔 해주어야 합니다. 

배열에서 절댓값이 가장 작은 값을 출력하고, 그 값을 배열에서 제거한다. 절댓값이 가장 작은 값이 여러개일 때는, 가장 작은 수를 출력하고, 그 값을 배열에서 제거한다.

 

즉, 절댓값이 작은 값이 앞으로 오게끔 해주면 됩니다. 절댓값이 같다면 원래의 수를 비교해서 더 작은 값을 앞으로 오게 해주면 되는데, 우선순위 큐는 앞서 말했듯이 기본적으로 오름차순 정렬이므로, 우리는 절댓값을 기준으로 정렬하는 것에만 신경쓰면 됩니다. 참고로, compare 함수를 구현할 때 return 값을 양수를 주면 순서를 바꾼다는 의미이고, 음수를 주면 바꾸지 않겠다는 의미입니다. 

PriorityQueue<Integer> pq = new PriorityQueue<Integer>(new Comparator<Integer>() {
	@Override
	public int compare(Integer o1, Integer o2) {
        if (Math.abs(o1) > Math.abs(o2)) {
            return Math.abs(o1) - Math.abs(o2);
        } else if(Math.abs(o1) == Math.abs(o2)) {
            return o1 - o2;
        } else {
            return -1;
        }
    }
});

 

위 코드를 한 나눠서 본다면

if (Math.abs(o1) > Math.abs(o2)) {
    return Math.abs(o1) - Math.abs(o2);
}

기본적으로 우선순위 큐는 오름차순으로 정렬되어 있는 상태에서, 절댓값을 기준으로 앞쪽 값이 더 크다면 순서를 바꿔줍니다.

else if(Math.abs(o1) == Math.abs(o2)) {
    return o1 - o2;
}

만일 절댓값을 기준으로 두 값이 같다면 순서를 바꾸지 않아도 됩니다.

 

💻 Code

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

public class BJ11286 {
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		StringBuilder sb = new StringBuilder();
		
		int N = Integer.parseInt(br.readLine());
		PriorityQueue<Integer> pq = new PriorityQueue<Integer>(new Comparator<Integer>() {
			@Override
			public int compare(Integer o1, Integer o2) {
				if (Math.abs(o1) > Math.abs(o2)) {
					return Math.abs(o1) - Math.abs(o2);
				} else if(Math.abs(o1) == Math.abs(o2)) {
					return o1 - o2;
				} else {
					return -1;
				}
			}
		});
		
		for (int i = 0; i < N; i++) {
			st = new StringTokenizer(br.readLine());
			int x = Integer.parseInt(st.nextToken());
			if (x == 0) {
				if (pq.isEmpty()) {
					sb.append(0).append("\n");
				} else {
					sb.append(pq.poll()).append("\n");
				}
			} else {
				pq.offer(x);
			}
		}
		System.out.println(sb);
	}

}