# heapq 활용

문제
https://school.programmers.co.kr/learn/courses/30/lessons/138477
프로그래머스
SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
문제 설명
- TV 프로그램 "명예의 전당"에서는 매일 가수의 점수가 발표되고, 시청자들의 문자 투표로 가수에게 점수 부여
- 매일 발표되는 명예의 전당에서, 가수의 점수가 상위 k번째 이내일 경우 해당 가수의 점수가 명예의 전당에 추가
- 초기에는 k일간 모든 점수가 명예의 전당에 올라가며, 그 이후부터는 새로운 가수의 점수가 기존 명예의 전당의 k번째 점수보다 높으면 추가되고, 기존 점수는 내려옴
- 이 문제는 매일 발표되는 명예의 전당의 최하위 점수를 구하는 문제
- 제한사항
3 ≤ k ≤ 100
7 ≤ score의 길이 ≤ 1,000
0 ≤ score[i] ≤ 2,000

정답 코드
import heapq
def solution(k, score):
honor = [] # 명예의 전당 (최소 힙)
answer = [] # 매일 발표된 최하위 점수
for s in score:
heapq.heappush(honor, s) # 점수를 명예의 전당에 추가
if len(honor) > k: # 명예의 전당 크기가 k를 초과하면
heapq.heappop(honor) # 가장 작은 점수를 제거 (최소 힙에서)
answer.append(honor[0]) # 현재 명예의 전당에서 최하위 점수 기록
return answer
- honor[0]: honor는 최소 힙이기 때문에, 가장 작은 값은 항상 honor[0]에 있음 → 이를 매일의 최하위 점수로 기록
heapq 이란?
- 개념
- heapq는 파이썬 내장 힙(Heap) 자료구조 모듈
- 기본은 최소 힙(min heap) 구조
→ 항상 가장 작은 값이 인덱스 0에 위치함 - 최대 힙은 지원하지 않음, 대신 음수로 바꿔 넣어 흉내낼 수 있음
- 특징
- 우선순위 큐(Priority Queue) 구현에 사용
- 정렬 없이도 최솟값/최댓값을 빠르게 꺼냄
- 삽입/삭제 시간 복잡도: O(log n)
- 기본 사용법 예제
import heapq # heapq 모듈 불러오기 (파이썬 표준 힙 라이브러리)
nums = [] # 빈 힙(리스트) 생성
heapq.heappush(nums, 5) # 5를 힙에 추가 → [5]
heapq.heappush(nums, 2) # 2를 추가 → [2, 5] (자동 정렬됨: 가장 작은 값이 앞으로)
heapq.heappush(nums, 8) # 8 추가 → [2, 5, 8] (힙 구조 유지)
print(heapq.heappop(nums)) # 2 출력: 가장 작은 값 (맨 앞의 값)을 꺼냄 → 남은 힙: [5, 8]
print(heapq.heappop(nums)) # 5 출력: 그다음 작은 값 → 남은 힙: [8]
- 최대 힙 만들기 (Tip)
import heapq # 힙 모듈 불러오기
nums = [] # 빈 리스트(힙) 생성
heapq.heappush(nums, -5) # -5를 추가 → 실제 값 5를 최대 힙처럼 다루기 위해 음수로 저장
heapq.heappush(nums, -2) # -2 추가 → 실제 값 2
heapq.heappush(nums, -8) # -8 추가 → 실제 값 8
print(-heapq.heappop(nums)) # 가장 작은 음수 값인 -8 꺼내고 다시 음수 붙여서 8 출력 → 실제로는 가장 큰 값 꺼낸 셈
첫 번째 시도 (실패)
def solution(k, score):
medi = []
answer = []
for i in range(len(score)):
medi.append(score[i])
medi.sort(reverse=True)
if len(medi) < k+1:
answer.append(medi[-1])
else:
answer.remove(medi[-1])
answer.append(medi[-1])
return answer
문제점
- answer.remove() → answer는 결과 리스트인데 여기서 값 제거는 오작동
- medi 크기 제한 안 함 → 계속 커져서 비효율
- 매번 정렬해서 시간 많이 소요→ 매번 반복해야되는거 아닌가??..
첫 번째 시도 (성공. 개선필요)
def solution(k, score):
medi = []
answer = []
for i in range(len(score)):
medi.append(score[i])
medi.sort(reverse=True)
if len(medi) < k+1:
answer.append(medi[-1])
else:
medi.remove(medi[-1])
answer.append(medi[-1])
return answer
개선점
- medi.sort(reverse=True) : 불필요한 정렬 계속 발생
- remove()는 O(n) 시간 소모
- pop() 활용하면 조금 낫지만, heapq가 더 적합
'코딩 테스트 연습 > [프로그래머스] Python' 카테고리의 다른 글
| [LV.3] 연습문제 > 카드 뭉치 (2) | 2025.07.25 |
|---|---|
| [LV.3] 연습문제 > 2016년 (3) | 2025.07.23 |
| [LV.3] 연습문제 > 콜라 문제 (3) | 2025.07.17 |
| [LV.3] 연습문제 > 푸드 파이트 대회 (0) | 2025.07.15 |
| [LV.3] 연습문제 > 가장 가까운 같은 글자 ⭐️ (1) | 2025.07.11 |