1"""
2μ€νκ³Ό ν νμ©
3Stack and Queue Applications
4
5μ€ν(LIFO)κ³Ό ν(FIFO) μλ£κ΅¬μ‘°λ₯Ό νμ©ν μκ³ λ¦¬μ¦ μμ μ
λλ€.
6"""
7
8from collections import deque
9from typing import List, Optional
10
11
12# =============================================================================
13# μ€ν ꡬν (리μ€νΈ κΈ°λ°)
14# =============================================================================
15class Stack:
16 """리μ€νΈ κΈ°λ° μ€ν ꡬν"""
17
18 def __init__(self):
19 self._items = []
20
21 def push(self, item):
22 self._items.append(item)
23
24 def pop(self):
25 if not self.is_empty():
26 return self._items.pop()
27 raise IndexError("Stack is empty")
28
29 def peek(self):
30 if not self.is_empty():
31 return self._items[-1]
32 raise IndexError("Stack is empty")
33
34 def is_empty(self):
35 return len(self._items) == 0
36
37 def size(self):
38 return len(self._items)
39
40
41# =============================================================================
42# ν ꡬν (deque κΈ°λ°)
43# =============================================================================
44class Queue:
45 """deque κΈ°λ° ν ꡬν (O(1) μ°μ°)"""
46
47 def __init__(self):
48 self._items = deque()
49
50 def enqueue(self, item):
51 self._items.append(item)
52
53 def dequeue(self):
54 if not self.is_empty():
55 return self._items.popleft()
56 raise IndexError("Queue is empty")
57
58 def front(self):
59 if not self.is_empty():
60 return self._items[0]
61 raise IndexError("Queue is empty")
62
63 def is_empty(self):
64 return len(self._items) == 0
65
66 def size(self):
67 return len(self._items)
68
69
70# =============================================================================
71# 1. κ΄νΈ κ²μ¦ (Valid Parentheses)
72# =============================================================================
73def is_valid_parentheses(s: str) -> bool:
74 """
75 κ΄νΈ λ¬Έμμ΄μ μ ν¨μ± κ²μ¬
76 μκ°λ³΅μ‘λ: O(n), 곡κ°λ³΅μ‘λ: O(n)
77 """
78 stack = []
79 mapping = {')': '(', '}': '{', ']': '['}
80
81 for char in s:
82 if char in mapping:
83 # λ«λ κ΄νΈμΌ λ
84 if not stack or stack[-1] != mapping[char]:
85 return False
86 stack.pop()
87 else:
88 # μ¬λ κ΄νΈμΌ λ
89 stack.append(char)
90
91 return len(stack) == 0
92
93
94# =============================================================================
95# 2. νμ νκΈ°λ² κ³μ° (Postfix Evaluation)
96# =============================================================================
97def evaluate_postfix(expression: str) -> int:
98 """
99 νμ νκΈ°λ² μμ κ³μ°
100 μ: "2 3 + 4 *" = (2 + 3) * 4 = 20
101 """
102 stack = []
103 operators = {'+', '-', '*', '/'}
104
105 for token in expression.split():
106 if token in operators:
107 b = stack.pop()
108 a = stack.pop()
109 if token == '+':
110 stack.append(a + b)
111 elif token == '-':
112 stack.append(a - b)
113 elif token == '*':
114 stack.append(a * b)
115 elif token == '/':
116 stack.append(int(a / b)) # μ μ λλμ
117 else:
118 stack.append(int(token))
119
120 return stack[0]
121
122
123# =============================================================================
124# 3. λ€μ ν° μμ (Next Greater Element)
125# =============================================================================
126def next_greater_element(arr: List[int]) -> List[int]:
127 """
128 κ° μμμ μ€λ₯Έμͺ½μμ μ²μμΌλ‘ λ ν° μμ μ°ΎκΈ°
129 μμΌλ©΄ -1 λ°ν
130 μκ°λ³΅μ‘λ: O(n), 곡κ°λ³΅μ‘λ: O(n)
131 """
132 n = len(arr)
133 result = [-1] * n
134 stack = [] # μΈλ±μ€ μ μ₯
135
136 for i in range(n):
137 # νμ¬ μμκ° μ€ν topλ³΄λ€ ν¬λ©΄
138 while stack and arr[i] > arr[stack[-1]]:
139 idx = stack.pop()
140 result[idx] = arr[i]
141 stack.append(i)
142
143 return result
144
145
146# =============================================================================
147# 4. μΌμΌ μ¨λ (Daily Temperatures)
148# =============================================================================
149def daily_temperatures(temperatures: List[int]) -> List[int]:
150 """
151 λ λ°λ»ν λ κΉμ§ λ©°μΉ μ κΈ°λ€λ €μΌ νλμ§ κ³μ°
152 μκ°λ³΅μ‘λ: O(n), 곡κ°λ³΅μ‘λ: O(n)
153 """
154 n = len(temperatures)
155 result = [0] * n
156 stack = [] # (μΈλ±μ€) μ μ₯
157
158 for i in range(n):
159 while stack and temperatures[i] > temperatures[stack[-1]]:
160 prev_idx = stack.pop()
161 result[prev_idx] = i - prev_idx
162 stack.append(i)
163
164 return result
165
166
167# =============================================================================
168# 5. μ΅μ μ€ν (Min Stack)
169# =============================================================================
170class MinStack:
171 """
172 O(1) μκ°μ μ΅μκ°μ λ°ννλ μ€ν
173 """
174
175 def __init__(self):
176 self.stack = []
177 self.min_stack = []
178
179 def push(self, val: int):
180 self.stack.append(val)
181 if not self.min_stack or val <= self.min_stack[-1]:
182 self.min_stack.append(val)
183
184 def pop(self):
185 if self.stack:
186 val = self.stack.pop()
187 if val == self.min_stack[-1]:
188 self.min_stack.pop()
189
190 def top(self) -> int:
191 return self.stack[-1] if self.stack else None
192
193 def get_min(self) -> int:
194 return self.min_stack[-1] if self.min_stack else None
195
196
197# =============================================================================
198# 6. ν λ κ°λ‘ μ€ν ꡬν
199# =============================================================================
200class StackUsingQueues:
201 """λ κ°μ νλ‘ μ€ν ꡬν"""
202
203 def __init__(self):
204 self.q1 = deque()
205 self.q2 = deque()
206
207 def push(self, x: int):
208 self.q2.append(x)
209 while self.q1:
210 self.q2.append(self.q1.popleft())
211 self.q1, self.q2 = self.q2, self.q1
212
213 def pop(self) -> int:
214 return self.q1.popleft() if self.q1 else None
215
216 def top(self) -> int:
217 return self.q1[0] if self.q1 else None
218
219 def empty(self) -> bool:
220 return len(self.q1) == 0
221
222
223# =============================================================================
224# 7. μ¬λΌμ΄λ© μλμ° μ΅λκ° (Monotonic Queue)
225# =============================================================================
226def max_sliding_window(nums: List[int], k: int) -> List[int]:
227 """
228 ν¬κΈ° kμΈ μ¬λΌμ΄λ© μλμ°μμ μ΅λκ° μ°ΎκΈ°
229 λ¨μ‘° κ°μ ν(Monotonic Deque) μ¬μ©
230 μκ°λ³΅μ‘λ: O(n), 곡κ°λ³΅μ‘λ: O(k)
231 """
232 result = []
233 dq = deque() # μΈλ±μ€ μ μ₯, κ°μ λ¨μ‘° κ°μ
234
235 for i in range(len(nums)):
236 # μλμ° λ²μ λ°μ μΈλ±μ€ μ κ±°
237 while dq and dq[0] < i - k + 1:
238 dq.popleft()
239
240 # νμ¬ κ°λ³΄λ€ μμ κ°λ€ μ κ±° (λ€μμλΆν°)
241 while dq and nums[dq[-1]] < nums[i]:
242 dq.pop()
243
244 dq.append(i)
245
246 # μλμ°κ° μμ±λλ©΄ μ΅λκ° μΆκ°
247 if i >= k - 1:
248 result.append(nums[dq[0]])
249
250 return result
251
252
253# =============================================================================
254# ν
μ€νΈ
255# =============================================================================
256def main():
257 print("=" * 60)
258 print("μ€νκ³Ό ν νμ© μμ ")
259 print("=" * 60)
260
261 # 1. κ΄νΈ κ²μ¦
262 print("\n[1] κ΄νΈ κ²μ¦")
263 test_cases = ["()", "()[]{}", "(]", "([)]", "{[]}"]
264 for tc in test_cases:
265 result = is_valid_parentheses(tc)
266 print(f" '{tc}' -> {result}")
267
268 # 2. νμ νκΈ°λ² κ³μ°
269 print("\n[2] νμ νκΈ°λ² κ³μ°")
270 expressions = ["2 3 +", "2 3 + 4 *", "5 1 2 + 4 * + 3 -"]
271 for expr in expressions:
272 result = evaluate_postfix(expr)
273 print(f" '{expr}' = {result}")
274
275 # 3. λ€μ ν° μμ
276 print("\n[3] λ€μ ν° μμ (Next Greater Element)")
277 arr = [4, 5, 2, 25]
278 result = next_greater_element(arr)
279 print(f" λ°°μ΄: {arr}")
280 print(f" κ²°κ³Ό: {result}")
281
282 # 4. μΌμΌ μ¨λ
283 print("\n[4] μΌμΌ μ¨λ")
284 temps = [73, 74, 75, 71, 69, 72, 76, 73]
285 result = daily_temperatures(temps)
286 print(f" μ¨λ: {temps}")
287 print(f" λκΈ° μΌμ: {result}")
288
289 # 5. μ΅μ μ€ν
290 print("\n[5] μ΅μ μ€ν (MinStack)")
291 min_stack = MinStack()
292 operations = [
293 ("push", 3), ("push", 5), ("getMin", None),
294 ("push", 2), ("push", 1), ("getMin", None),
295 ("pop", None), ("getMin", None)
296 ]
297 for op, val in operations:
298 if op == "push":
299 min_stack.push(val)
300 print(f" push({val})")
301 elif op == "pop":
302 min_stack.pop()
303 print(f" pop()")
304 elif op == "getMin":
305 print(f" getMin() = {min_stack.get_min()}")
306
307 # 6. μ¬λΌμ΄λ© μλμ° μ΅λκ°
308 print("\n[6] μ¬λΌμ΄λ© μλμ° μ΅λκ°")
309 nums = [1, 3, -1, -3, 5, 3, 6, 7]
310 k = 3
311 result = max_sliding_window(nums, k)
312 print(f" λ°°μ΄: {nums}, k={k}")
313 print(f" κ° μλμ° μ΅λκ°: {result}")
314
315 print("\n" + "=" * 60)
316
317
318if __name__ == "__main__":
319 main()