널리 잘 알려진 자료구조 중 최대 힙이 있다. 최대 힙을 이용하여 다음과 같은 연산을 지원하는 프로그램을 작성하시오.
프로그램은 처음에 비어있는 배열에서 시작하게 된다.
첫째 줄에 연산의 개수 N(1 ≤ N ≤ 100,000)이 주어진다. 다음 N개의 줄에는 연산에 대한 정보를 나타내는 정수 x가 주어진다. 만약 x가 자연수라면 배열에 x라는 값을 넣는(추가하는) 연산이고, x가 0이라면 배열에서 가장 큰 값을 출력하고 그 값을 배열에서 제거하는 경우이다. 입력되는 자연수는 231보다 작다.
입력에서 0이 주어진 횟수만큼 답을 출력한다. 만약 배열이 비어 있는 경우인데 가장 큰 값을 출력하라고 한 경우에는 0을 출력하면 된다.
13
0
1
2
0
0
3
2
1
0
0
0
0
0
0
2
1
3
2
1
0
0
일단 너무 오랜만의 문제 해결이라 고민을 많이 해봤다.
일단 당장 생각나는 파이썬 라이브러리 중의 하나는 리스트 밖에 없었다.
일단 리스트를 사용해서 문제를 해결해보려 했다.
사실 성능을 생각하지 않고 문제를 해결하고자 하면 쉽게 풀 수 있다.
그래서 처음 생각한 코드는 다음과 같았다.
N = int(input())
l = []
for _ in range(N) :
x = int(input())
if x == 0 :
leng = len(l)
if leng == 0 :
print(0)
else :
a = l[leng-1]
print(a)
l.remove(a)
else :
l.append(x)
l.sort()
당연히 시간 초과가 떴다.
파이썬에서 제공하는 sort() 함수는 TimSort라는 정렬 알고리즘을 사용한다.
(이에 대해서는 나중에 다뤄보도록 하겠다.)
아무튼 파이썬 라이브러리에 내장된 heap 함수를 사용해야겠다고 생각했다.
파이썬에서는 최소 힙은 구현되어있지만 최대 힙은 구현되어있지 않다.
최소 힙은 함수 하나면 자료 구조 내에 담겨있는 값들 중 최소값을 출력하고 제거된다.
그래서 이것저것 고민했지만 오랜만에 알고리즘 문제를 푸는 나에게 뇌는 도와주지 않았다.
그러다가 블로그 하나를 참고해서 최소 힙으로 최대 힙을 해결하는 것을 찾았다.
부호를 이용해서 최소 힙을 최대 힙으로 둔갑하는 것이었다.
부호만 붙이면 최소 힙에 담겨있는 최대 값은 그대로 최소값이 된다.
출력할 때만 다시 부호를 떼면 최대값을 반환할 수 있다.
그래서 짠 코드는 다음과 같다.
import heapq as hq
import sys
N = int(input())
heap = []
for _ in range(N) :
x = int(sys.stdin.readline())
if x == 0 :
leng = len(heap)
if leng == 0 :
print(0)
else :
a = -hq.heappop(heap)
print(a)
else :
hq.heappush(heap, -x)