๊ฐ๋
๋ฐ ์ ์
ํ์ ์ข
๋ฅ
ํ์ ๊ตฌ์กฐ
Python heapq ๋ชจ๋
์ต๋ ํ ๊ตฌํ
์ฐ์ ์์ ํ
๊ตฌํ ์ฝ๋
์ค์ ๋ฌธ์
ํ ๋ฌธ์ ์ ํ ์ ๋ฆฌ
์๊ฐ๋ณต์ก๋
ํ(Heap)์ ์์ ์ด์ง ํธ๋ฆฌ ๊ธฐ๋ฐ์ ์๋ฃ๊ตฌ์กฐ ๋ก, ํธ๋ฆฌ์์ ์ต๋/์ต์๊ฐ์ ๋น ๋ฅด๊ฒ ๊ตฌํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
ํ = ์ฐ์ ์์ ํ๋ฅผ ๊ตฌํํ๊ธฐ ์ํ ์์ ์ด์ง ํธ๋ฆฌ
์์ ์ด์ง ํธ๋ฆฌ : ๋ง์ง๋ง ๋ ๋ฒจ์ ์ ์ธํ ๋ชจ๋ ๋ ๋ฒจ์ด ์ฑ์์ ธ ์๊ณ , ๋ง์ง๋ง ๋ ๋ฒจ์ ์ผ์ชฝ๋ถํฐ ์ฑ์์ง
ํ ์์ฑ : ๋ถ๋ชจ์ ์์ ์ฌ์ด์ ๋์ ๊ด๊ณ ์ ์ง
์ต๋/์ต์๊ฐ ์ ๊ทผ : O(1)
์ฝ์
/์ญ์ : O(log n)
1.3 ์ผ์ ์ ํ์ ์
์์
์ค๋ช
์๊ธ์ค ๋๊ธฐ
๊ฐ์ฅ ์๊ธํ ํ์๊ฐ ๋จผ์ ์น๋ฃ
์์
์ค์ผ์ค๋ง
์ฐ์ ์์ ๋์ ์์
๋ถํฐ ์ฒ๋ฆฌ
๋คํธ์ํฌ ํจํท
์ค์๋์ ๋ฐ๋ผ ํจํท ์ฒ๋ฆฌ
๊ฒ์ AI
๊ฐ์ฅ ์ํ์ ์ธ ์ ์ ๋จผ์ ๊ณต๊ฒฉ
1.4 ํ vs ์ด์ง ํ์ ํธ๋ฆฌ
ํน์ฑ
ํ (Heap)
BST (์ด์ง ํ์ ํธ๋ฆฌ)
๋ชฉ์
์ต๋/์ต์ ๋น ๋ฅธ ์ ๊ทผ
์ ๋ ฌ๋ ๋ฐ์ดํฐ ์ ์ง
์ ๋ ฌ
๋ถ๋ชจ > ์์ (๋๋ <)
์ผ์ชฝ < ๋ถ๋ชจ < ์ค๋ฅธ์ชฝ
๊ตฌ์กฐ
์์ ์ด์ง ํธ๋ฆฌ
์ด์ง ํธ๋ฆฌ
์ต๋/์ต์ ์ ๊ทผ
O(1)
O(log n) ~ O(n)
ํ์
O(n)
O(log n) ํ๊ท
2.1 ์ต๋ ํ (Max Heap)
์ต๋ ํ: ๋ถ๋ชจ ๋
ธ๋ โฅ ์์ ๋
ธ๋
100
/ \
90 80
/ \ / \
70 60 50 40
ํน์ง:
- ๋ฃจํธ๊ฐ ์ต๋๊ฐ
- ๋ถ๋ชจ๋ ํญ์ ์์๋ณด๋ค ํฌ๊ฑฐ๋ ๊ฐ์
- ํ์ ์ฌ์ด์๋ ๋์ ๊ด๊ณ ์์
2.2 ์ต์ ํ (Min Heap)
์ต์ ํ: ๋ถ๋ชจ ๋
ธ๋ โค ์์ ๋
ธ๋
10
/ \
20 30
/ \ / \
40 50 60 70
ํน์ง:
- ๋ฃจํธ๊ฐ ์ต์๊ฐ
- ๋ถ๋ชจ๋ ํญ์ ์์๋ณด๋ค ์๊ฑฐ๋ ๊ฐ์
- ํ์ ์ฌ์ด์๋ ๋์ ๊ด๊ณ ์์
๊ตฌ๋ถ
์ต๋ ํ (Max Heap)
์ต์ ํ (Min Heap)
์กฐ๊ฑด
๋ถ๋ชจ โฅ ์์
๋ถ๋ชจ โค ์์
๋ฃจํธ
์ต๋๊ฐ
์ต์๊ฐ
์ฉ๋
๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ, ์ต๋๊ฐ ๋ฐ๋ณต ์ถ์ถ
์ค๋ฆ์ฐจ์ ์ ๋ ฌ, ์ต์๊ฐ ๋ฐ๋ณต ์ถ์ถ
Python
์์ ๋ณํ ํ์
heapq ๊ธฐ๋ณธ
์์ ์ด์ง ํธ๋ฆฌ๋ ๋ฐฐ์ด๋ก ํจ์จ์ ์ผ๋ก ํํ ๊ฐ๋ฅ
์ต์ ํ ์์:
10
/ \
20 30
/ \ /
40 50 60
๋ฐฐ์ด: [10, 20, 30, 40, 50, 60]
์ธ๋ฑ์ค: 0 1 2 3 4 5
์ธ๋ฑ์ค ๊ด๊ณ (0-based):
- ๋ถ๋ชจ: (i - 1) // 2
- ์ผ์ชฝ ์์: 2 * i + 1
- ์ค๋ฅธ์ชฝ ์์: 2 * i + 2
์ฝ์
(Insert) - Heapify Up
์ฝ์
๊ณผ์ (์ต์ ํ์ 5 ์ฝ์
):
1. ๋ง์ง๋ง ์์น์ ์ฝ์
10 10
/ \ / \
20 30 โ 20 30
/ \ / \ / \ / \
40 50 60 [5] 40 50 60 5
2. ๋ถ๋ชจ์ ๋น๊ตํ๋ฉฐ ์๋ก ์ด๋ (Heapify Up)
10 10 5
/ \ / \ / \
20 30 โ 20 5 โ 20 10
/ \ / \ / \ / \ / \ / \
40 50 60 5 40 50 60 30 40 50 60 30
๊ฒฐ๊ณผ: 5๊ฐ ๋ฃจํธ๋ก ์ด๋
์ญ์ (Delete) - Heapify Down
์ญ์ ๊ณผ์ (์ต์ ํ์์ ๋ฃจํธ ์ญ์ ):
1. ๋ฃจํธ(์ต์๊ฐ) ๋ฐํ, ๋ง์ง๋ง ๋
ธ๋๋ฅผ ๋ฃจํธ๋ก ์ด๋
5 30
/ \ / \
20 10 โ 20 10
/ \ / / \
40 50 30 40 50
2. ์์๊ณผ ๋น๊ตํ๋ฉฐ ์๋๋ก ์ด๋ (Heapify Down)
30 10
/ \ / \
20 10 โ 20 30
/ \ / \
40 50 40 50
๊ฒฐ๊ณผ: 10์ด ๋ฃจํธ๋ก ์ด๋
Python์ heapq ๋ชจ๋์ **์ต์ ํ(Min Heap)**์ ๊ตฌํํฉ๋๋ค.
import heapq
# ๊ธฐ๋ณธ ์ฌ์ฉ๋ฒ
heap = [] # ๋น ํ ์์ฑ
heapq .heappush (heap , 3 ) # ์ฝ์
heapq .heappush (heap , 1 )
heapq .heappush (heap , 2 )
print (heap ) # [1, 3, 2]
min_val = heapq .heappop (heap ) # ์ต์๊ฐ ์ถ์ถ
print (min_val ) # 1
print (heap ) # [2, 3]
ํจ์
์ค๋ช
์๊ฐ๋ณต์ก๋
heappush(heap, item)
์์ ์ฝ์
O(log N)
heappop(heap)
์ต์๊ฐ ์ ๊ฑฐ ๋ฐ ๋ฐํ
O(log N)
heapify(list)
๋ฆฌ์คํธ๋ฅผ ํ์ผ๋ก ๋ณํ
O(N)
heappushpop(heap, item)
push ํ pop (ํจ์จ์ )
O(log N)
heapreplace(heap, item)
pop ํ push (ํจ์จ์ )
O(log N)
nsmallest(n, iterable)
๊ฐ์ฅ ์์ n๊ฐ ๋ฐํ
O(N log n)
nlargest(n, iterable)
๊ฐ์ฅ ํฐ n๊ฐ ๋ฐํ
O(N log n)
4.3 ํจ์๋ณ ์์ธ ์ค๋ช
๋ฐ ์์
4.3.1 heappush(heap, item)
import heapq
heap = []
heapq .heappush (heap , 5 )
heapq .heappush (heap , 3 )
heapq .heappush (heap , 8 )
heapq .heappush (heap , 1 )
print (heap ) # [1, 3, 8, 5]
# ์ฐธ๊ณ : ๋ด๋ถ ๋ฐฐ์ด ์์์ ์ ๋ ฌ ์์๋ ๋ค๋ฆ
# ํ์ง๋ง heappop() ํ๋ฉด ํญ์ ์ต์๊ฐ์ด ๋์ด
import heapq
heap = [1 , 3 , 8 , 5 ]
heapq .heapify (heap ) # ํ ๊ตฌ์กฐ ๋ณด์ฅ
min_val = heapq .heappop (heap )
print (min_val ) # 1
print (heap ) # [3, 5, 8]
# ์ฐ์ pop์ผ๋ก ์ ๋ ฌ๋ ์์ ์ป๊ธฐ
heap = [5 , 3 , 8 , 1 , 2 ]
heapq .heapify (heap )
sorted_list = [heapq .heappop (heap ) for _ in range (len (heap ))]
print (sorted_list ) # [1, 2, 3, 5, 8]
import heapq
# ๊ธฐ์กด ๋ฆฌ์คํธ๋ฅผ ํ์ผ๋ก ๋ณํ
numbers = [5 , 3 , 8 , 1 , 2 , 7 ]
heapq .heapify (numbers ) # O(N)
print (numbers ) # [1, 2, 7, 5, 3, 8]
# ์ฃผ์: heapify๋ in-place๋ก ๋ณํ
# ์ ๋ฆฌ์คํธ๋ฅผ ๋ฐํํ์ง ์์
4.3.4 heappushpop(heap, item)
import heapq
# push ํ pop (push + pop๋ณด๋ค ํจ์จ์ )
heap = [1 , 3 , 5 , 7 ]
result = heapq .heappushpop (heap , 2 )
print (result ) # 1 (์ต์๊ฐ ๋ฐํ)
print (heap ) # [2, 3, 5, 7]
# ์ฌ์ฉ ์: ์์ k๊ฐ๋ง ์ ์ง
def top_k_smallest (nums , k ):
return heapq .nsmallest (k , nums )
4.3.5 heapreplace(heap, item)
import heapq
# pop ํ push (pop + push๋ณด๋ค ํจ์จ์ )
heap = [1 , 3 , 5 , 7 ]
result = heapq .heapreplace (heap , 10 )
print (result ) # 1 (๋จผ์ pop๋ ๊ฐ)
print (heap ) # [3, 7, 5, 10]
# ์ฃผ์: heapreplace๋ ๋น ํ์์ ์๋ฌ ๋ฐ์
4.3.6 nsmallest / nlargest
import heapq
numbers = [5 , 3 , 8 , 1 , 2 , 7 , 9 , 4 ]
# ๊ฐ์ฅ ์์ 3๊ฐ
smallest_3 = heapq .nsmallest (3 , numbers )
print (smallest_3 ) # [1, 2, 3]
# ๊ฐ์ฅ ํฐ 3๊ฐ
largest_3 = heapq .nlargest (3 , numbers )
print (largest_3 ) # [9, 8, 7]
# ํค ํจ์ ์ฌ์ฉ
students = [
{'name' : 'Kim' , 'score' : 85 },
{'name' : 'Lee' , 'score' : 92 },
{'name' : 'Park' , 'score' : 78 }
]
# ์ ์ ๊ธฐ์ค ์์ 2๋ช
top_2 = heapq .nlargest (2 , students , key = lambda x : x ['score' ])
print (top_2 )
# [{'name': 'Lee', 'score': 92}, {'name': 'Kim', 'score': 85}]
4.4 ํ peek (์ต์๊ฐ ํ์ธ๋ง)
import heapq
heap = [1 , 3 , 5 , 7 ]
# peek: ์ ๊ฑฐ ์์ด ์ต์๊ฐ ํ์ธ
min_val = heap [0 ] # O(1)
print (min_val ) # 1
print (heap ) # [1, 3, 5, 7] (๋ณ๊ฒฝ ์์)
# ์ฃผ์: heap[1]์ด ๋ ๋ฒ์งธ๋ก ์์ ๊ฐ์ ์๋!
# ๋ ๋ฒ์งธ ์ต์๊ฐ์ ์๋ ค๋ฉด pop ํ ๋ค์ peek
Python์ heapq๋ ์ต์ ํ๋ง ์ง์ ํ๋ฏ๋ก, ์ต๋ ํ์ ์์(-) ๋ณํ ์ผ๋ก ๊ตฌํํฉ๋๋ค.
import heapq
# ์ต๋ ํ ๊ตฌํ: ์์๋ก ์ ์ฅํ๊ณ ์์๋ก ๊บผ๋ด๊ธฐ
max_heap = []
# ์ฝ์
: ์์๋ก ์ ์ฅ
heapq .heappush (max_heap , - 5 )
heapq .heappush (max_heap , - 3 )
heapq .heappush (max_heap , - 8 )
heapq .heappush (max_heap , - 1 )
print (max_heap ) # [-8, -3, -5, -1]
# ์ถ์ถ: ์์๋ฅผ ๋ค์ ์์๋ก
max_val = - heapq .heappop (max_heap )
print (max_val ) # 8 (์ต๋๊ฐ)
# ์ต๋๊ฐ ํ์ธ (peek)
max_peek = - max_heap [0 ]
print (max_peek ) # 5
5.2 ์ต๋ ํ ๋ํผ ํจ์
import heapq
class MaxHeap :
"""์ต๋ ํ ๋ํผ ํด๋์ค"""
def __init__ (self ):
self .heap = []
def push (self , val ):
"""๊ฐ ์ฝ์
(์์๋ก ๋ณํ)"""
heapq .heappush (self .heap , - val )
def pop (self ):
"""์ต๋๊ฐ ์ถ์ถ (์์๋ก ๋ณํ)"""
return - heapq .heappop (self .heap )
def peek (self ):
"""์ต๋๊ฐ ํ์ธ"""
return - self .heap [0 ]
def __len__ (self ):
return len (self .heap )
def __bool__ (self ):
return bool (self .heap )
# ์ฌ์ฉ ์์
max_heap = MaxHeap ()
max_heap .push (5 )
max_heap .push (3 )
max_heap .push (8 )
max_heap .push (1 )
print (max_heap .peek ()) # 8
print (max_heap .pop ()) # 8
print (max_heap .pop ()) # 5
5.3 ํํ์ ์ด์ฉํ ๋ฐฉ๋ฒ
import heapq
# (์ฐ์ ์์, ๊ฐ) ํํ ์ฌ์ฉ
# ์ฐ์ ์์๊ฐ ๊ฐ์ผ๋ฉด ๊ฐ์ผ๋ก ๋น๊ต
# ์ต์ ํ (๊ธฐ๋ณธ)
min_heap = []
heapq .heappush (min_heap , (1 , 'low' ))
heapq .heappush (min_heap , (3 , 'high' ))
heapq .heappush (min_heap , (2 , 'medium' ))
print (heapq .heappop (min_heap )) # (1, 'low')
# ์ต๋ ํ (์ฐ์ ์์์ ์์)
max_heap = []
heapq .heappush (max_heap , (- 1 , 'low' ))
heapq .heappush (max_heap , (- 3 , 'high' ))
heapq .heappush (max_heap , (- 2 , 'medium' ))
priority , value = heapq .heappop (max_heap )
print (- priority , value ) # 3 high
์ฐ์ ์์ ํ(Priority Queue)๋ ์ฐ์ ์์์ ๋ฐ๋ผ ์์๊ฐ ์ฒ๋ฆฌ๋๋ ํ ์
๋๋ค.
์ผ๋ฐ ํ: FIFO (์ ์
์ ์ถ)
์ฐ์ ์์ ํ: ์ฐ์ ์์ ๋์ ๊ฒ์ด ๋จผ์ ์ถ๋ ฅ
6.2 ํ์ผ๋ก ์ฐ์ ์์ ํ ๊ตฌํ
import heapq
class PriorityQueue :
"""ํ ๊ธฐ๋ฐ ์ฐ์ ์์ ํ"""
def __init__ (self ):
self .heap = []
self .count = 0 # ๋์ผ ์ฐ์ ์์ ์ฒ๋ฆฌ์ฉ
def push (self , item , priority ):
"""
์์ดํ
์ฝ์
priority๊ฐ ์์์๋ก ๋์ ์ฐ์ ์์ (์ต์ ํ)
"""
# (์ฐ์ ์์, ์ฝ์
์์, ์์ดํ
) - ๋์ผ ์ฐ์ ์์๋ฉด ์ฝ์
์์๋ก
heapq .heappush (self .heap , (priority , self .count , item ))
self .count += 1
def pop (self ):
"""๊ฐ์ฅ ๋์ ์ฐ์ ์์ ์์ดํ
์ถ์ถ"""
if self .heap :
return heapq .heappop (self .heap )[2 ] # item๋ง ๋ฐํ
return None
def peek (self ):
"""๊ฐ์ฅ ๋์ ์ฐ์ ์์ ์์ดํ
ํ์ธ"""
if self .heap :
return self .heap [0 ][2 ]
return None
def is_empty (self ):
return len (self .heap ) == 0
# ์ฌ์ฉ ์์
pq = PriorityQueue ()
pq .push ('์น๋ฃ' , 1 ) # ๋์ ์ฐ์ ์์
pq .push ('์๋ฐฉ์ ์ข
' , 3 ) # ๋ฎ์ ์ฐ์ ์์
pq .push ('๊ฒ์ง' , 2 ) # ์ค๊ฐ ์ฐ์ ์์
print (pq .pop ()) # ์น๋ฃ
print (pq .pop ()) # ๊ฒ์ง
print (pq .pop ()) # ์๋ฐฉ์ ์ข
6.3 Python queue.PriorityQueue
from queue import PriorityQueue
# PriorityQueue ์ฌ์ฉ (์ค๋ ๋ ์์ )
pq = PriorityQueue ()
pq .put ((1 , '๊ธด๊ธ' ))
pq .put ((3 , '๋ณดํต' ))
pq .put ((2 , '์ค์' ))
print (pq .get ()) # (1, '๊ธด๊ธ')
print (pq .get ()) # (2, '์ค์')
print (pq .get ()) # (3, '๋ณดํต')
# ์ฃผ์: heapq๊ฐ ๋ ๋น ๋ฆ (์ค๋ ๋ ์์ ์ค๋ฒํค๋ ์์)
# ๋จ์ผ ์ค๋ ๋ ์ฝ๋ฉํ
์คํธ์์๋ heapq ๊ถ์ฅ
7.1 ์ง์ ํ ๊ตฌํ (๊ต์ก์ฉ)
class MinHeap :
"""์ต์ ํ ์ง์ ๊ตฌํ (๊ต์ก์ฉ)"""
def __init__ (self ):
self .heap = []
def parent (self , i ):
return (i - 1 ) // 2
def left_child (self , i ):
return 2 * i + 1
def right_child (self , i ):
return 2 * i + 2
def swap (self , i , j ):
self .heap [i ], self .heap [j ] = self .heap [j ], self .heap [i ]
def push (self , val ):
"""์ฝ์
ํ heapify up"""
self .heap .append (val )
self ._heapify_up (len (self .heap ) - 1 )
def _heapify_up (self , i ):
"""์๋ก ์ด๋ํ๋ฉฐ ํ ์์ฑ ์ ์ง"""
while i > 0 and self .heap [self .parent (i )] > self .heap [i ]:
self .swap (i , self .parent (i ))
i = self .parent (i )
def pop (self ):
"""์ต์๊ฐ ์ถ์ถ ํ heapify down"""
if not self .heap :
return None
min_val = self .heap [0 ]
last = self .heap .pop ()
if self .heap :
self .heap [0 ] = last
self ._heapify_down (0 )
return min_val
def _heapify_down (self , i ):
"""์๋๋ก ์ด๋ํ๋ฉฐ ํ ์์ฑ ์ ์ง"""
smallest = i
left = self .left_child (i )
right = self .right_child (i )
if left < len (self .heap ) and self .heap [left ] < self .heap [smallest ]:
smallest = left
if right < len (self .heap ) and self .heap [right ] < self .heap [smallest ]:
smallest = right
if smallest != i :
self .swap (i , smallest )
self ._heapify_down (smallest )
def peek (self ):
return self .heap [0 ] if self .heap else None
def __len__ (self ):
return len (self .heap )
# ์ฌ์ฉ ์์
heap = MinHeap ()
heap .push (5 )
heap .push (3 )
heap .push (8 )
heap .push (1 )
print (heap .pop ()) # 1
print (heap .pop ()) # 3
print (heap .pop ()) # 5
print (heap .pop ()) # 8
7.2 ์ฝ๋ฉํ
์คํธ์ฉ ๊ฐ๋จ ๊ตฌํ
import heapq
# ์ต์ ํ (๊ธฐ๋ณธ)
min_heap = []
heapq .heappush (min_heap , 3 )
heapq .heappush (min_heap , 1 )
heapq .heappush (min_heap , 2 )
while min_heap :
print (heapq .heappop (min_heap )) # 1, 2, 3
# ์ต๋ ํ (์์ ๋ณํ)
max_heap = []
for val in [3 , 1 , 2 ]:
heapq .heappush (max_heap , - val )
while max_heap :
print (- heapq .heappop (max_heap )) # 3, 2, 1
# ๋ฆฌ์คํธ๋ฅผ ํ์ผ๋ก ๋ณํ
nums = [5 , 3 , 8 , 1 , 2 ]
heapq .heapify (nums ) # O(n)
print (nums ) # [1, 2, 8, 5, 3]
8.1 ๋ฌธ์ 1: K๋ฒ์งธ ํฐ ์์ (LeetCode 215)
์ ์ ๋ฐฐ์ด nums์ ์ ์ k๊ฐ ์ฃผ์ด์ง ๋,
๋ฐฐ์ด์์ k๋ฒ์งธ๋ก ํฐ ์์๋ฅผ ๋ฐํํ์์ค.
์์:
nums = [3,2,1,5,6,4], k = 2
return = 5 (์ ๋ ฌํ๋ฉด [6,5,4,3,2,1]์์ 2๋ฒ์งธ)
import heapq
def findKthLargest (nums , k ):
"""
๋ฐฉ๋ฒ 1: ์ต๋ ํ ์ฌ์ฉ
- ๋ชจ๋ ์์๋ฅผ ์ต๋ ํ์ ๋ฃ๊ณ k๋ฒ pop
"""
max_heap = [- x for x in nums ]
heapq .heapify (max_heap )
for _ in range (k - 1 ):
heapq .heappop (max_heap )
return - heapq .heappop (max_heap )
def findKthLargest_v2 (nums , k ):
"""
๋ฐฉ๋ฒ 2: ์ต์ ํ์ผ๋ก k๊ฐ๋ง ์ ์ง
- ํฌ๊ธฐ k์ ์ต์ ํ ์ ์ง
- ํ์ ๋ฃจํธ๊ฐ k๋ฒ์งธ ํฐ ๊ฐ
"""
min_heap = nums [:k ]
heapq .heapify (min_heap )
for num in nums [k :]:
if num > min_heap [0 ]:
heapq .heapreplace (min_heap , num )
return min_heap [0 ]
# ํ
์คํธ
print (findKthLargest ([3 ,2 ,1 ,5 ,6 ,4 ], 2 )) # 5
print (findKthLargest ([3 ,2 ,3 ,1 ,2 ,4 ,5 ,5 ,6 ], 4 )) # 4
8.2 ๋ฌธ์ 2: ๋ ๋งต๊ฒ (ํ๋ก๊ทธ๋๋จธ์ค)
๋ชจ๋ ์์์ ์ค์ฝ๋น ์ง์๋ฅผ K ์ด์์ผ๋ก ๋ง๋ค์ด์ผ ํฉ๋๋ค.
์ค์ฝ๋น ์ง์๊ฐ ๊ฐ์ฅ ๋ฎ์ ๋ ์์์ ์์ด ์๋ก์ด ์์์ ๋ง๋ญ๋๋ค.
์ ์์์ ์ค์ฝ๋น = ๊ฐ์ฅ ๋ฎ์ ์์ + (๋ ๋ฒ์งธ๋ก ๋ฎ์ ์์ * 2)
๋ชจ๋ ์์์ ์ค์ฝ๋น ์ง์๊ฐ K ์ด์์ด ๋ ๋๊น์ง ๋ฐ๋ณตํฉ๋๋ค.
๋ช ๋ฒ ์์ด์ผ ํ๋์ง returnํ์์ค.
์์:
scoville = [1, 2, 3, 9, 10, 12], K = 7
return = 2
import heapq
def solution (scoville , K ):
"""
๋ ๋งต๊ฒ - ์ต์ ํ ํ์ฉ
์ ๋ต:
1. ์ค์ฝ๋น ์ง์๋ฅผ ์ต์ ํ์ผ๋ก ๊ด๋ฆฌ
2. ์ต์๊ฐ์ด K ๋ฏธ๋ง์ด๋ฉด ๋ ๊ฐ ๊บผ๋ด์ ์๊ธฐ
3. ๋ ์ด์ ์์ ์ ์์ผ๋ฉด -1 ๋ฐํ
"""
heapq .heapify (scoville ) # O(n)
count = 0
while scoville [0 ] < K :
if len (scoville ) < 2 :
return - 1 # ๋ ์ด์ ์์ ์ ์์
# ๊ฐ์ฅ ์ ๋งค์ด ๊ฒ ๋ ๊ฐ ๊บผ๋ด๊ธฐ
first = heapq .heappop (scoville )
second = heapq .heappop (scoville )
# ์๊ธฐ
new_scoville = first + second * 2
heapq .heappush (scoville , new_scoville )
count += 1
return count
# ํ
์คํธ
print (solution ([1 , 2 , 3 , 9 , 10 , 12 ], 7 )) # 2
8.3 ๋ฌธ์ 3: ๋์คํฌ ์ปจํธ๋กค๋ฌ (ํ๋ก๊ทธ๋๋จธ์ค)
ํ๋๋์คํฌ๊ฐ ์์ฒญ์ ์ฒ๋ฆฌํ ๋, ์์ฒญ์ด ๋ค์ด์จ ์์๋๋ก ์ฒ๋ฆฌํ์ง ์๊ณ
ํ์ฌ ์์ ์์ ๊ฐ์ฅ ์งง์ ์์
๋ถํฐ ์ฒ๋ฆฌํ๋ฉด ํ๊ท ๋๊ธฐ ์๊ฐ์ ์ค์ผ ์ ์์ต๋๋ค.
jobs[i] = [์์ฒญ ์์ , ์์ ์๊ฐ]
๋ชจ๋ ์์ฒญ์ ํ๊ท ๋ฐํ ์๊ฐ์ ์ต์ํํ์์ค.
์์:
jobs = [[0, 3], [1, 9], [2, 6]]
return = 9
import heapq
def solution (jobs ):
"""
๋์คํฌ ์ปจํธ๋กค๋ฌ - SJF (Shortest Job First)
์ ๋ต:
1. ํ์ฌ ์์ ์์ ์ฒ๋ฆฌ ๊ฐ๋ฅํ ์์
์ค ๊ฐ์ฅ ์งง์ ๊ฒ ์ ํ
2. ์ต์ ํ์ผ๋ก ์์ ์๊ฐ ๊ธฐ์ค ๊ด๋ฆฌ
"""
jobs .sort (key = lambda x : x [0 ]) # ์์ฒญ ์์ ์ ์ ๋ ฌ
n = len (jobs )
heap = [] # (์์ ์๊ฐ, ์์ฒญ ์์ )
total_time = 0
current_time = 0
job_index = 0
while job_index < n or heap :
# ํ์ฌ ์์ ๊น์ง ๋์ฐฉํ ์์
์ ํ์ ์ถ๊ฐ
while job_index < n and jobs [job_index ][0 ] <= current_time :
heapq .heappush (heap , (jobs [job_index ][1 ], jobs [job_index ][0 ]))
job_index += 1
if heap :
# ๊ฐ์ฅ ์งง์ ์์
์ฒ๋ฆฌ
duration , arrival = heapq .heappop (heap )
current_time += duration
total_time += current_time - arrival # ๋ฐํ ์๊ฐ
else :
# ์ฒ๋ฆฌํ ์์
์ด ์์ผ๋ฉด ๋ค์ ์์
์์ ์ผ๋ก ์ด๋
current_time = jobs [job_index ][0 ]
return total_time // n
# ํ
์คํธ
print (solution ([[0 , 3 ], [1 , 9 ], [2 , 6 ]])) # 9
8.4 ๋ฌธ์ 4: ์ด์ค ์ฐ์ ์์ ํ (ํ๋ก๊ทธ๋๋จธ์ค)
์ด์ค ์ฐ์ ์์ ํ๋ ๋ค์ ์ฐ์ฐ์ ์ง์ํฉ๋๋ค:
- I ์ซ์: ํ์ ์ฃผ์ด์ง ์ซ์ ์ฝ์
- D 1: ์ต๋๊ฐ ์ญ์
- D -1: ์ต์๊ฐ ์ญ์
๋ชจ๋ ์ฐ์ฐ์ ์ฒ๋ฆฌํ ํ ํ๊ฐ ๋น์ด์์ผ๋ฉด [0, 0]
๋น์ด์์ง ์์ผ๋ฉด [์ต๋๊ฐ, ์ต์๊ฐ] ๋ฐํ
์์:
operations = ["I 16", "I -5643", "D -1", "D 1", "D 1", "I 123", "D -1"]
return = [0, 0]
import heapq
def solution (operations ):
"""
์ด์ค ์ฐ์ ์์ ํ
์ ๋ต:
์ต์ ํ๊ณผ ์ต๋ ํ ๋์ ๊ด๋ฆฌ + ์ญ์ ์ฌ๋ถ ์ถ์
"""
min_heap = []
max_heap = []
entry_count = {} # ์ ํจํ ์์ ์ถ์
for op in operations :
cmd , val = op .split ()
val = int (val )
if cmd == 'I' :
heapq .heappush (min_heap , val )
heapq .heappush (max_heap , - val )
entry_count [val ] = entry_count .get (val , 0 ) + 1
elif cmd == 'D' :
# ์ ํจํ์ง ์์ ์์ ์ ๊ฑฐ
while min_heap and entry_count .get (min_heap [0 ], 0 ) == 0 :
heapq .heappop (min_heap )
while max_heap and entry_count .get (- max_heap [0 ], 0 ) == 0 :
heapq .heappop (max_heap )
if val == 1 and max_heap : # ์ต๋๊ฐ ์ญ์
max_val = - heapq .heappop (max_heap )
entry_count [max_val ] -= 1
elif val == - 1 and min_heap : # ์ต์๊ฐ ์ญ์
min_val = heapq .heappop (min_heap )
entry_count [min_val ] -= 1
# ์ ํจํ์ง ์์ ์์ ์ ๋ฆฌ
while min_heap and entry_count .get (min_heap [0 ], 0 ) == 0 :
heapq .heappop (min_heap )
while max_heap and entry_count .get (- max_heap [0 ], 0 ) == 0 :
heapq .heappop (max_heap )
if not min_heap :
return [0 , 0 ]
return [- max_heap [0 ], min_heap [0 ]]
# ํ
์คํธ
print (solution (["I 16" , "D 1" ])) # [0, 0]
print (solution (["I 7" , "I 5" , "I -5" , "D -1" ])) # [7, 5]
8.5 ๋ฌธ์ 5: ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ (ํ ํ์ฉ)
import heapq
def dijkstra (graph , start ):
"""
๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ - ํ ํ์ฉ
graph: {๋
ธ๋: [(๊ฑฐ๋ฆฌ, ์ฐ๊ฒฐ๋
ธ๋), ...]}
"""
distances = {node : float ('inf' ) for node in graph }
distances [start ] = 0
heap = [(0 , start )] # (๊ฑฐ๋ฆฌ, ๋
ธ๋)
while heap :
current_dist , current_node = heapq .heappop (heap )
# ์ด๋ฏธ ์ฒ๋ฆฌ๋ ๋
ธ๋๋ฉด ์คํต
if current_dist > distances [current_node ]:
continue
for dist , neighbor in graph [current_node ]:
new_dist = current_dist + dist
if new_dist < distances [neighbor ]:
distances [neighbor ] = new_dist
heapq .heappush (heap , (new_dist , neighbor ))
return distances
# ์์
graph = {
'A' : [(1 , 'B' ), (4 , 'C' )],
'B' : [(2 , 'C' ), (5 , 'D' )],
'C' : [(1 , 'D' )],
'D' : []
}
print (dijkstra (graph , 'A' ))
# {'A': 0, 'B': 1, 'C': 3, 'D': 4}
9. ํ ๋ฌธ์ ์ ํ ์ ๋ฆฌ
9.1 ํ์ผ๋ก ํ์ด์ผ ํ๋ ์ ํ
ํค์๋
ํ๋ฅ
์ค๋ช
"์ต๋/์ต์ ๋น๋ฒ"
๋์
์ต๋๊ฐ ๋๋ ์ต์๊ฐ์ ๋ฐ๋ณต์ ์ผ๋ก ๊ตฌํจ
"K๋ฒ์งธ"
๋์
K๋ฒ์งธ ํฐ/์์ ๊ฐ
"์ฐ์ ์์"
๋์
์ฐ์ ์์์ ๋ฐ๋ฅธ ์ฒ๋ฆฌ
"๋ค์ต์คํธ๋ผ"
100%
์ต๋จ ๊ฒฝ๋ก ์๊ณ ๋ฆฌ์ฆ
"์์ K๊ฐ"
๋์
๊ฐ์ฅ ํฐ/์์ K๊ฐ ์์
"์ ๋ ฌ + ์ค๊ฐ"
์ค๊ฐ
์ค๊ฐ๊ฐ ์ฐพ๊ธฐ (๋ ๊ฐ์ ํ ์ฌ์ฉ)
๋ฌธ์ ์์ ๋ค์ ํจํด์ด ๋ณด์ด๋ฉด ํ์ ๊ณ ๋ คํ์ธ์:
1. ์ต๋/์ต์๊ฐ์ ์ฌ๋ฌ ๋ฒ ๊ตฌํด์ผ ํ๋ ๋ฌธ์
โ ๋งค๋ฒ ์ ๋ ฌํ๋ฉด ๋นํจ์จ์ , ํ ์ฌ์ฉ
2. K๋ฒ์งธ ์์๋ฅผ ์ฐพ๋ ๋ฌธ์
โ ํ์ผ๋ก K๊ฐ๋ง ์ ์ง
3. ์ฐ์ ์์ ๊ธฐ๋ฐ ์ฒ๋ฆฌ
โ ์ฐ์ ์์ ํ๋ก ๊ตฌํ
4. ๋์ ์ผ๋ก ์ ๋ ฌ ์ํ๋ฅผ ์ ์งํด์ผ ํ๋ ๋ฌธ์
โ ์ฝ์
/์ญ์ ํ์๋ ์ต๋/์ต์ ๋น ๋ฅด๊ฒ ์ ๊ทผ
5. ๋ค์ต์คํธ๋ผ, ํ๋ฆผ ์๊ณ ๋ฆฌ์ฆ
โ ํ ๊ธฐ๋ฐ ๊ตฌํ์ด ํจ์จ์
9.3 ๋ํ์ ์ธ ํ ๋ฌธ์ ๋ค
๋ฌธ์ ์ ํ
์์
K๋ฒ์งธ ์์
K๋ฒ์งธ ํฐ ์, ์์ K๊ฐ
ํฉ์น๊ธฐ
๋ ๋งต๊ฒ, ๋ ํฉ์น๊ธฐ
์ค์ผ์ค๋ง
๋์คํฌ ์ปจํธ๋กค๋ฌ, ์์
์ค์ผ์ค๋ง
์ต๋จ ๊ฒฝ๋ก
๋ค์ต์คํธ๋ผ, ํ๋ฆผ
์ค๊ฐ๊ฐ
์คํธ๋ฆฌ๋ฐ ์ค๊ฐ๊ฐ
์ด์ค ํ
์ด์ค ์ฐ์ ์์ ํ
10.1 ํ ์ฐ์ฐ ์๊ฐ๋ณต์ก๋
์ฐ์ฐ
์๊ฐ๋ณต์ก๋
์ค๋ช
heappush
O(log N)
์ฝ์
ํ heapify up
heappop
O(log N)
์ ๊ฑฐ ํ heapify down
heapify
O(N)
๋ฆฌ์คํธ๋ฅผ ํ์ผ๋ก ๋ณํ
peek (heap[0])
O(1)
์ต์๊ฐ ํ์ธ
nsmallest(k)
O(N log k)
๊ฐ์ฅ ์์ k๊ฐ
nlargest(k)
O(N log k)
๊ฐ์ฅ ํฐ k๊ฐ
10.2 ํ ์ ๋ ฌ ์๊ฐ๋ณต์ก๋
# ํ ์ ๋ ฌ
def heap_sort (arr ):
heapq .heapify (arr ) # O(N)
return [heapq .heappop (arr ) for _ in range (len (arr ))] # O(N log N)
# ์ ์ฒด ์๊ฐ๋ณต์ก๋: O(N log N)
# ๊ณต๊ฐ๋ณต์ก๋: O(1) (in-place) ๋๋ O(N)
10.3 ์ ๋ ฌ vs ํ ๋น๊ต
์ํฉ
์ ๋ ฌ
ํ
์ ์ฒด ์ ๋ ฌ ํ์
O(N log N) โ
O(N log N)
์์ K๊ฐ๋ง ํ์
O(N log N)
O(N log K) โ
๋์ ์ฝ์
/์ญ์
O(N)
O(log N) โ
์ต๋/์ต์ 1๋ฒ๋ง
O(N) โ
O(N)
import heapq
# 1. ๊ธฐ์กด ๋ฆฌ์คํธ๋ฅผ ํ์ผ๋ก (in-place)
nums = [5 , 3 , 8 , 1 ]
heapq .heapify (nums ) # nums๊ฐ ์ง์ ๋ณ๊ฒฝ๋จ
# 2. ์์ K๊ฐ (์ ๋ ฌ๋ณด๋ค ํจ์จ์ )
top_3 = heapq .nlargest (3 , nums ) # O(N log 3)
# 3. ํํ ํ์ฉ (๋ค์ค ๊ธฐ์ค ์ ๋ ฌ)
# (์ฐ์ ์์1, ์ฐ์ ์์2, ๊ฐ)
heap = []
heapq .heappush (heap , (1 , 'a' , 'data1' ))
heapq .heappush (heap , (1 , 'b' , 'data2' ))
# 4. ์์ ๋ณํ์ผ๋ก ์ต๋ ํ
heapq .heappush (heap , - value )
max_val = - heapq .heappop (heap )
import heapq
# ๋น ํ์์ pop ์ ์๋ฌ
heap = []
heapq .heappop (heap ) # IndexError
# ํญ์ ํ์ธ ํ pop
if heap :
heapq .heappop (heap )
# heapify๋ in-place (๋ฐํ๊ฐ None)
nums = [5 , 3 , 8 ]
result = heapq .heapify (nums ) # result๋ None!
# nums๊ฐ ์ง์ ๋ณ๊ฒฝ๋จ
ํ vs ๋ค๋ฅธ ์๋ฃ๊ตฌ์กฐ ์ ํ
์๋ฃ๊ตฌ์กฐ
์ต์/์ต๋ ์ ๊ทผ
์ฝ์
์ญ์
ํ์
์ ๋ ฌ ๋ฐฐ์ด
O(1)
O(N)
O(N)
O(log N)
ํ
O(1)
O(log N)
O(log N)
O(N)
BST (๊ท ํ)
O(log N)
O(log N)
O(log N)
O(log N)
ํ ์ ํ ๊ธฐ์ค:
์ต๋/์ต์๋ง ์์ฃผ ํ์ โ ํ โ
ํน์ ๊ฐ ํ์์ด ์์ฃผ ํ์ โ BST
์ ์ฒด ์ ๋ ฌ ํ์ โ ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ