diff --git a/binary-tree-level-order-traversal/dusunax.py b/binary-tree-level-order-traversal/dusunax.py new file mode 100644 index 000000000..02a579187 --- /dev/null +++ b/binary-tree-level-order-traversal/dusunax.py @@ -0,0 +1,82 @@ +''' +# Leetcode 102. Binary Tree Level Order Traversal + +do level order traversal + +``` +πŸ’‘ why use BFS?: +BFS is the recommended approach, because it aligns with the problem's concept of processing the binary tree level by level and avoids issues related to recursion depth, making the solution both cleaner and more reliable. + +- DFS doesn't naturally support level-by-level traversal, so we need an extra variable like "dep" (depth). +- BFS is naturally designed for level traversal, making it a better fit for the problem. +- additionally, BFS can avoid potential stack overflow. +``` + +## A. BFS + +### re-structuring the tree into a queue: +- use the queue for traverse the binary tree by level. + +### level traversal: +- pop the leftmost node +- append the node's value to current level's array +- enqueue the left and right children to queue +- can only process nodes at the current level, because of level_size. + +## B. DFS +- travase with a dep parameter => dp(node, dep) +- store the traversal result +''' +class Solution: + ''' + A. BFS + TC: O(n) + SC: O(n) + ''' + def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + result = [] # SC: O(n) + queue = deque([root]) # SC: O(n) + + while queue: # TC: O(n) + level_size = len(queue) + level = [] + + for _ in range(level_size): + node = queue.popleft() + level.append(node.val) + + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + result.append(level) + + return result + + ''' + B. DFS + TC: O(n) + SC: O(n) + ''' + def levelOrderDP(self, root: Optional[TreeNode]) -> List[List[int]]: + result = [] # SC: O(n) + + def dp(node, dep): + if node is None: + return + + if len(result) <= dep: + result.append([]) + + result[dep].append(node.val) + + dp(node.left, dep + 1) + dp(node.right, dep + 1) + + dp(root, 0) # TC: O(n) call stack + + return result diff --git a/counting-bits/dusunax.py b/counting-bits/dusunax.py new file mode 100644 index 000000000..eb98a98e7 --- /dev/null +++ b/counting-bits/dusunax.py @@ -0,0 +1,42 @@ +''' +# 338. Counting Bits + +0λΆ€ν„° nκΉŒμ§€μ˜ μ΄μ§„μˆ˜μ—μ„œ 1의 개수 μ„ΈκΈ° + +## 풀이A. 브루투포슀 +- μ „λΆ€ κ³„μ‚°ν•˜κΈ° + +## 풀이B. DP +``` +μ΄μ§„μˆ˜ = (μ΄μ§„μˆ˜ >> 1) + (μ΄μ§„μˆ˜ & 1) +``` +- `i >> 1`: i의 λΉ„νŠΈλ₯Ό 였λ₯Έμͺ½μœΌλ‘œ 1λΉ„νŠΈ 이동(맨 였λ₯Έμͺ½ ν•œ μΉΈ 버림), `i // 2`와 κ°™μŒ +- `i & 1`: `i`의 λ§ˆμ§€λ§‰ λΉ„νŠΈκ°€ 1인지 확인 (1이면 1 μΆ”κ°€, 0이면 패슀) +- DP ν…Œμ΄λΈ”μ—μ„œ 이전 계산(i >> 1) κ²°κ³Όλ₯Ό κ°€μ Έμ™€μ„œ ν˜„μž¬ 계산(i & 1) κ²°κ³Όλ₯Ό λ”ν•œλ‹€. +''' +class Solution: + ''' + A. brute force + SC: O(n log n) + TC: O(n) + ''' + def countBitsBF(self, n: int) -> List[int]: + result = [] + + for i in range(n + 1): # TC: O(n) + result.append(bin(i).count('1')) # TC: O(log n) + + return result + + ''' + B. DP + SC: O(n) + TC: O(n) + ''' + def countBits(self, n: int) -> List[int]: + dp = [0] * (n + 1) + + for i in range(1, n + 1): # TC: O(n) + dp[i] = dp[i >> 1] + (i & 1) # TC: O(1) + + return dp diff --git a/house-robber-ii/dusunax.py b/house-robber-ii/dusunax.py new file mode 100644 index 000000000..a936c10c1 --- /dev/null +++ b/house-robber-ii/dusunax.py @@ -0,0 +1,48 @@ +''' +# 213. House Robber II + +house roober 1 + circular array + +## Solution +solve by using two cases: +- robbing from the first house to the last house +- robbing from the second house to the last house +''' +class Solution: + ''' + A. pass indices to function + TC: O(n) + SC: O(1) + ''' + def rob(self, nums: Lit[int]) -> int: + if len(nums) == 1: + return nums[0] + + def robbing(start, end): + prev, maxAmount = 0, 0 + + for i in range(start, end): + prev, maxAmount = maxAmount, max(maxAmount, prev + nums[i]) + + return maxAmount + + return max(robbing(0, len(nums) - 1), robbing(1, len(nums))) + + ''' + B. pass list to function + TC: O(n) + SC: O(n) (list slicing) + ''' + def robWithSlicing(self, nums: List[int]) -> int: + if len(nums) == 1: + return nums[0] + + def robbing(nums): + prev, maxAmount = 0, 0 + + for num in nums: + prev, maxAmount = maxAmount, max(maxAmount, prev + num) + + return maxAmount + + return max(robbing(nums[1:]), robbing(nums[:-1])) diff --git a/meeting-rooms-ii/dusunax.py b/meeting-rooms-ii/dusunax.py new file mode 100644 index 000000000..3fd4bc4d4 --- /dev/null +++ b/meeting-rooms-ii/dusunax.py @@ -0,0 +1,59 @@ +''' +# 253. Meeting Rooms II + +μ΅œμ†Œ νž™ Min Heap을 μ‚¬μš©ν•˜μ—¬ 회의 μ’…λ£Œ μ‹œκ°„μ„ μ €μž₯ν•©λ‹ˆλ‹€. μ΅œμ†Œ νž™μ˜ κΈΈμ΄λŠ” ν•„μš”ν•œ νšŒμ˜μ‹€ κ°œμˆ˜μž…λ‹ˆλ‹€. + +## κ°œλ… +``` +πŸ’‘ μ΅œμ†Œ νž™ Min Heap +- νž™μ€ μ™„μ „ 이진 νŠΈλ¦¬μ΄λ‹€. +- λΆ€λͺ¨ λ…Έλ“œμ˜ 값이 μžμ‹ λ…Έλ“œμ˜ 값보닀 μž‘λ‹€. +- μ΅œμ†Œκ°’μ„ λ£¨νŠΈμ— 두기 λ•Œλ¬Έμ— μ΅œμ†Œκ°’μ„ μ°ΎλŠ” μ‹œκ°„λ³΅μž‘λ„κ°€ O(1)이닀. +``` +``` +πŸ’‘ μ™„μ „ 이진 트리 +- 트리의 λͺ¨λ“  레벨이 μ™„μ „νžˆ μ±„μ›Œμ Έ 있고, λ§ˆμ§€λ§‰ λ ˆλ²¨μ€ μ™Όμͺ½λΆ€ν„° μ±„μš΄λ‹€. +- μ‚½μž…κ³Ό μ‚­μ œλŠ” O(log n)의 μ‹œκ°„λ³΅μž‘λ„λ₯Ό κ°€μ§„λ‹€. + - μ‚½μž…μ€ 트리의 λ§ˆμ§€λ§‰ λ…Έλ“œμ— μ‚½μž…ν•˜κ³  버블업을 μ§„ν–‰ν•œλ‹€. + - μ‚­μ œλŠ” 트리의 루트 λ…Έλ“œλ₯Ό μ‚­μ œν•˜κ³ , λ²„λΈ”λ‹€μš΄μ„ μ§„ν–‰ν•œλ‹€. +``` + +## νšŒμ˜μ‹€ μž¬μ‚¬μš© 쑰건 +κ°€μž₯ λ¨Όμ € λλ‚˜λŠ” νšŒμ˜μ™€ λ‹€μŒ 회의 μ‹œμž‘μ„ λΉ„κ΅ν•˜μ—¬, λ‹€μŒ 회의 μ‹œμž‘μ΄ κ°€μž₯ λ¨Όμ € λλ‚˜λŠ” νšŒμ˜λ³΄λ‹€ ν¬κ±°λ‚˜ κ°™λ‹€λ©΄, 같은 νšŒμ˜μ‹€μ„ μ‚¬μš© κ°€λŠ₯ν•˜λ‹€. + +## 풀이 +``` +μ΅œμ†Œ νž™μ˜ 길이 = μ‚¬μš© 쀑인 νšŒμ˜μ‹€ 개수 = ν•„μš”ν•œ νšŒμ˜μ‹€ 개수 +``` +1. 회의 μ‹œμž‘ μ‹œκ°„μ„ κΈ°μ€€μœΌλ‘œ μ •λ ¬ +2. 회의 배열을 μˆœνšŒν•˜λ©° 회의 μ’…λ£Œ μ‹œκ°„μ„ μ΅œμ†Œ νž™μ— μ €μž₯ +3. νšŒμ˜μ‹€μ„ μž¬μ‚¬μš©ν•  수 μžˆλŠ” 경우, κ°€μž₯ λ¨Όμ € λλ‚˜λŠ” 회의 μ‚­μ œ ν›„ μƒˆ 회의 μ’…λ£Œ μ‹œκ°„ μΆ”κ°€(ν•΄λ‹Ή νšŒμ˜μ‹€μ˜ μ’…λ£Œ μ‹œκ°„ μ—…λ°μ΄νŠΈ) +4. μ΅œμ’… μ‚¬μš© 쀑인 νšŒμ˜μ‹€ 개수λ₯Ό λ°˜ν™˜ + +## μ‹œκ°„ & 곡간 λ³΅μž‘λ„ + +### TC is O(n log n) +- 회의 λ°°μ—΄ μ •λ ¬: O(n log n) +- 회의 λ°°μ—΄ 순회: O(n) +- μ΅œμ†Œ νž™ μ‚½μž… & μ‚­μ œ: O(log n) + +### SC is O(n) +- μ΅œμ†Œ νž™: μ΅œμ•…μ˜ 경우 O(n) +''' +from heapq import heappush, heappop + +class Solution: + def minMeetingRooms(self, intervals: List[Interval]) -> int: + if not intervals: + return 0 + + intervals.sort(key=lambda x: x.start) + + min_heap = [] + for interval in intervals: + if min_heap and min_heap[0] <= interval.start: + heappop(min_heap) + + heappush(min_heap, interval.end) + + return len(min_heap) diff --git a/meeting-rooms/dusunax.py b/meeting-rooms/dusunax.py index 28f2407c2..618802711 100644 --- a/meeting-rooms/dusunax.py +++ b/meeting-rooms/dusunax.py @@ -6,12 +6,11 @@ - 회의 μ‹œκ°„μ΄ κ²ΉμΉ˜μ§€ μ•ŠλŠ” 경우 회의λ₯Ό μ§„ν–‰ν•  수 μžˆλ‹€. ## 풀이 - - intervalsλ₯Ό μ‹œμž‘ μ‹œκ°„μœΌλ‘œ μ •λ ¬ν•œλ‹€. - μ‹œκ°„ κ²ΉμΉ¨ μ—¬λΆ€λ₯Ό ν™•μΈν•œλ‹€. - κ²ΉμΉ˜λŠ” 경우 False, κ²ΉμΉ˜μ§€ μ•ŠλŠ” 경우 Trueλ₯Ό λ°˜ν™˜ν•œλ‹€. -## μ‹œκ°„ λ³΅μž‘λ„ +## μ‹œκ°„ & 곡간 λ³΅μž‘λ„ ### TC is O(n log n) - μ •λ ¬ μ‹œκ°„: O(n log n) @@ -19,7 +18,6 @@ ### SC is O(1) - μΆ”κ°€ μ‚¬μš© 곡간 μ—†μŒ - ''' class Solution: def canAttendMeetings(self, intervals: List[List[int]]) -> bool: