이중 우선순위 큐를 구현해야 한다. 이중 우선순위 큐는 최대값 삭제 연산, 최소값 삭제 연산이 가능하며, 최종적으로 큐에 수가 남아있는 경우 '최대값 최소값' 형태로 반환해야 하며, 큐에 수가 없을 경우 'EMPTY'를 반환해야 한다.
from typing import List
from heapq import heappush, heappop, nlargest
def solution(operations : List):
heap:List[str] = list() # 리스트를 힙으로 활용할 것, 디폴트는 min heap
for operation in operations:
op, value = operation.split()
if op == 'I': # 삽입 연산
heappush(heap, int(value))
elif heap: # 최대값 / 최소값 삭제 연산, heap에 원소가 있을 때만 실행
if value=='1': # 최대값 삭제 연산
heap.remove(*nlargest(1, heap)) # 1번째로 큰 값 찾아서 삭제(nlargest의 반환 타입은 list임)
else: # 최소값 삭제 연산
heappop(heap) # min heap이 default이므로 heappop시 최소값 삭제
return [*nlargest(1, heap), heappop(heap)] if heap else [0, 0] # heap에 원소가 있으면 [최대값, 최소값] 반환, 비었으면 [0, 0] 반환
def main():
case1 = ["I 16", "I -5643", "D -1", "D 1", "D 1", "I 123", "D -1"] # [0, 0]
case2 = ["I -45", "I 653", "D 1", "I -642", "I 45", "I 97", "D 1", "D -1", "I 333"] # [333, -45]
print(solution(case1))
print(solution(case2))
main()
이중 우선순위 큐 백준 버전 : 프로그래머스 문제와 동일하지만, 테스트 케이스에 대해 좀 더 엄격한 문제이다.
import sys
from typing import List
from heapq import heappush, heappop
input = sys.stdin.readline
class MinMaxHeap:
def __init__(self, num_of_operations):
'''
생성자
- self.inserted : 현재 이중우선순위큐에 삽입된 수들의 유효성을 관리하는 변수
- self.minHeap, self.maxHeap : 이중 우선순위큐를 구현하기 위한 min Heap, max Heap
- self.count : 유효한 수들의 개수를 관리하는 변수
'''
self.inserted: List[bool] = [False for _ in range(num_of_operations)]
self.minHeap: List[int] = list()
self.maxHeap: List[int] = list()
self.count: int = 0
def empty(self) -> bool:
'''
현재 이중우선순위큐가 비었는지 확인하는 연산
'''
return self.count == 0
def push(self, value: int, idx: int) -> None:
'''
이중우선순위큐 삽입 연산
- 각 힙에 value 값과 함께 현재 입력 순서 인덱스를 삽입한다.
- idx번째 순서로 삽입된 수는 유효한 수임을 체크
- 최대힙을 구현하기 위해 value에 -기호를 붙혀 삽입해야 한다.
'''
self.inserted[idx] = True
self.count += 1
heappush(self.minHeap, (value, idx))
heappush(self.maxHeap, (-value, idx))
def popMin(self) -> int:
'''
이중우선순위큐 최소값 pop 연산
- validation : 검증을 위한 boolean 변수
- inserted[idx]가 True인 유효한 수가 반환될 때까지 최소 힙에서 반복해서 heappop연산을 수행한다.
- 유효하지 않은 수(False)가 반환되었다는 것은 이미 max heap에서 삭제된 수라는 뜻
'''
validation = False
while not validation:
result, idx = heappop(self.minHeap)
validation = self.inserted[idx]
self.inserted[idx] = False
self.count -= 1
return result
def popMax(self) -> int:
'''
이중우선순위큐 최소값 pop 연산
- validation : 검증을 위한 boolean 변수
- inserted[idx]가 True인 유효한 수가 반환될 때까지 최대 힙에서 반복해서 heappop연산을 수행한다.
- 유효하지 않은 수(False)가 반환되었다는 것은 이미 min heap에서 삭제된 수라는 뜻
- max heap을 구현하기 위해 value가 음수로 저장되어 있으므로 부호를 반전하여 값을 반환해주어야 함
'''
validation = False
while not validation:
result, idx = heappop(self.maxHeap)
validation = self.inserted[idx]
self.inserted[idx] = False
self.count -= 1
return -result
def peekMin(self) -> int:
'''
이중우선순위큐 최소값 peek 연산
- 마지막 반환 시에 pop으로 반환하게 되면 최대, 최소 값을 온전하게 반환하지 못함(큐에 원소가 하나 있는 경우)
- 마찬가지로 유효하지 않은 값은 모두 pop해버리고, 유효한 값이 큐의 최 상단에 있으면 이를 반환
'''
while not self.inserted[self.minHeap[0][1]]:
heappop(self.minHeap)
return self.minHeap[0][0]
def peekMax(self) -> int:
'''
이중우선순위큐 최대값 peek 연산
- 마지막 반환 시에 pop으로 반환하게 되면 최대, 최소 값을 온전하게 반환하지 못함(큐에 원소가 하나 있는 경우)
- 마찬가지로 유효하지 않은 값은 모두 pop해버리고, 유효한 값이 큐의 최 상단에 있으면 이를 반환
'''
while not self.inserted[self.maxHeap[0][1]]:
heappop(self.maxHeap)
return -self.maxHeap[0][0]
def solution():
num_of_testcases = int(input())
for _ in range(num_of_testcases):
num_of_operations = int(input())
heap = MinMaxHeap(num_of_operations)
for idx in range(num_of_operations):
op, value = input().rstrip().split()
value = int(value)
if op == 'I':
heap.push(value, idx)
elif op == 'D' and not heap.empty():
if value == 1:
heap.popMax()
else:
heap.popMin()
print('EMPTY') if heap.empty() else print(*[heap.peekMax(), heap.peekMin()])
solution()
🙏 문제 접근 방법 및 코드에 대한 피드백과 질문은 환영입니다!
본 문제의 다른 풀이 및 피드백, 전체 문제 풀이 순서는 위 알고리즘 스터디 Repository에서도 확인 가능합니다.