본문 바로가기

Algorithm

백준 11279 최대 힙 Java

힙 자료구조를 사용해야 하는 최대 힙 문제이다

 

문제의 내용은 2가지 연산을 지원하는데

0인 경우엔 최대힙에서 가장 윗부분 가장 큰 수를 삭제 후 출력

0이 아닌 경우엔 최대힙에 삽입하는 것이다.

 

힙 정렬을 배웠지만

힙 정렬은 삽입 없이 삭제 후 다시 힙으로 만들어 주는 과정을 반복하지

삽입과 삭제를 따로 구현하지 않아서

힙에서 삽입과 삭제를 따로 구현하려니까

생각대로 잘 안됐다.

 

코드를 천천히 살펴보면서 꼭 복습해보자.

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
60
61
62
 
public class Q11279 {
    public static int [] heap = new int[100001];
    public static int size = 0;
    public static StringBuilder sb = new StringBuilder();
 
    public static void swap(int x, int y) {
        int temp = heap[x];
        heap[x] = heap[y];
        heap[y] = temp;
    }
    public static void push(int x) {
        heap[++size] = x;
        //삽입한 것 부터 힙인지 확인, 힙이아니면 계속 부모노드로 올라가고 힙이면 break
        for(int i=size; i>1; i/=2) {
            if(heap[i/2< heap[i]) {
                swap(i/2, i);
            } else {
                break;
            }
        }
    }
 
    public static void pop() {
        sb.append(heap[1]+"\n");
        heap[1= heap[size];
        heap[size--= 0;
        for(int i=1; i*2<=size;) { //삭제 후 1에서 부터 힙으로 만들어주는 과정
            if(heap[i] > heap[i*2&& heap[i] > heap[i*2+1]) {
                break;
            }else if(heap[i*2> heap[i*2+1]) {
                swap(i, i*2);
                i = i*2;
            } else {
                swap(i, i*2+1);
                i = i*2+1;
            }
        }
    }
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        for(int i=0; i<n; i++) {
            int k = Integer.parseInt(reader.readLine());
            if(k==0) {
                if(size == 0) {
                    sb.append(0+"\n");
                } else {
                    pop();
                }
            } else {
                push(k);
            }
        }
        System.out.print(sb.toString());
    }
}
 
 

이 문제를 힙을 구현하지 않고도 해결할 수 있는 방법이 있는데

바로 PriorityQueue(우선순위 큐)이다.

PriorityQueue는 삭제 연산을 했을 때 우선순위가 가장 높은 것을 우선으로 삭제한다.

자바에서는 라이브러리에 있는 우선순위 큐를 특별한 설정 없이 사용했을 때

최소 힙처럼 최솟값을 우선으로 삭제한다.

이 문제에서는 최댓값을 삭제 후 출력해줘야 하므로

우선순위 큐에 삽입시에 -1을 곱해서 음수 형태로 삽입시켜줌으로써

최댓값이 우선순위가 가장 높게 해주고

삭제 시에 삭제된 값에 -1을 곱해서 출력하면 양수 형태로 출력되게 된다.

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
 
public class Q11279_ver2 {
 
    public static void main(String[] args) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(reader.readLine());
        Queue<Integer> q = new PriorityQueue<>();
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<n; i++) {
            
            int k = Integer.parseInt(reader.readLine());
            if(k==0) {
                if(q.isEmpty()) {
                    sb.append(0+"\n");
                } else {
                    //출력할 땐 다시 -1을 곱해서 양수로 
                    sb.append(q.poll()*-1+"\n");
                }
            } else {
                //최댓값을 삭제해야 하므로 삽입 시 -1을 곱해준다.
                q.add(k*-1);
            }
        }
        System.out.print(sb.toString());
    }
}
 
 

PriorityQueue를 사용한 코드가 훨씬 깔끔하다.

PriorityQueue도 힙 자료구조를 사용하여 구현한 것이기 때문에

시간 복잡도는 최대 힙이나 우선순위 큐나 둘 다 삽입, 삭제 시에 O(logn)의 시간 복잡도를 가진다.

 

하지만 두 코드를 전부 백준에서 채점하면 최대 힙을 구현한 코드가 좀 더 빠른 실행 시간을 가진다.

'Algorithm' 카테고리의 다른 글

백준 2252 줄 세우기 Java  (0) 2019.08.12
백준 9375 패션왕 신해빈 Java  (0) 2019.08.09
백준 14888 연산자 끼워넣기 Java  (0) 2019.08.07
백준 2606 바이러스 Java  (0) 2019.08.07
백준 1717 집합의 표현 Java  (0) 2019.08.07