From ad3e83aa4d6735d9d97cac6b62de566e6cd8d05a Mon Sep 17 00:00:00 2001 From: seungriyou Date: Sun, 22 Jun 2025 10:44:13 +0900 Subject: [PATCH 1/5] solve(w13): 252. Meeting Rooms --- meeting-rooms/seungriyou.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 meeting-rooms/seungriyou.py diff --git a/meeting-rooms/seungriyou.py b/meeting-rooms/seungriyou.py new file mode 100644 index 000000000..63742bcf7 --- /dev/null +++ b/meeting-rooms/seungriyou.py @@ -0,0 +1,23 @@ +# https://leetcode.com/problems/meeting-rooms/ + +from typing import List + +class Solution: + def canAttendMeetings(self, intervals: List[List[int]]) -> bool: + """ + [Complexity] + - TC: O(nlogn) + - SC: O(1) (inplace sorting) + + [Approach] + intervals를 start 기준으로 오름차순 정렬 후, 앞 회의의 끝 시간 > 뒷 회의의 시작 시간이라면 겹치는 것이므로 False 반환 + """ + # sort intervals (by start) + intervals.sort() + + for i in range(1, len(intervals)): + # prev_e > curr_s 라면 False + if intervals[i - 1][1] > intervals[i][0]: + return False + + return True From 81186eb0248d21db3be9493f080949d7555095ab Mon Sep 17 00:00:00 2001 From: seungriyou Date: Sun, 22 Jun 2025 10:45:13 +0900 Subject: [PATCH 2/5] solve(w13): 235. Lowest Common Ancestor of a Binary Search Tree --- .../seungriyou.py | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 lowest-common-ancestor-of-a-binary-search-tree/seungriyou.py diff --git a/lowest-common-ancestor-of-a-binary-search-tree/seungriyou.py b/lowest-common-ancestor-of-a-binary-search-tree/seungriyou.py new file mode 100644 index 000000000..4ba3fb66e --- /dev/null +++ b/lowest-common-ancestor-of-a-binary-search-tree/seungriyou.py @@ -0,0 +1,54 @@ +# https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ + +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor_recur(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + """ + [Complexity] + - TC: O(height) + - SC: O(height) (call stack) + + [Approach] + 어떤 node와 두 노드 p, q 간의 관계를 다음의 케이스로 나누어 볼 수 있다. + 1) p와 q가 모두 현재 node 보다 작다면 --> left subtree로 내려가 살펴보기 + 2) p와 q가 모두 현재 node 보다 크다면 --> right subtree로 내려가 살펴보기 + 3) p와 q가 현재 node의 두 child subtree에 각각 존재한다면 --> 현재 node가 p, q의 LCA + """ + + def find_lca(node): + # 1) p와 q가 모두 현재 node 보다 작다면 --> left subtree로 내려가 살펴보기 + if p.val < node.val > q.val: + return find_lca(node.left) + # 2) p와 q가 모두 현재 node 보다 크다면 --> right subtree로 내려가 살펴보기 + if p.val > node.val < q.val: + return find_lca(node.right) + # 3) p와 q가 현재 node의 두 child subtree에 각각 존재한다면 --> 현재 node가 p, q의 LCA + return node + + return find_lca(root) + + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + """ + [Complexity] + - TC: O(height) + - SC: O(1) + + [Approach] + 이전 recursive 풀이를 iterative 하게 풀이할 수 있다. + """ + while root: + # 1) p와 q가 모두 현재 node 보다 작다면 --> left subtree로 내려가 살펴보기 + if p.val < root.val > q.val: + root = root.left + # 2) p와 q가 모두 현재 node 보다 크다면 --> right subtree로 내려가 살펴보기 + elif p.val > root.val < q.val: + root = root.right + # 3) p와 q가 현재 node의 두 child subtree에 각각 존재한다면 --> 현재 node가 p, q의 LCA + else: + return root From d12d8eede8105104643b1f4345284d282bac9f18 Mon Sep 17 00:00:00 2001 From: seungriyou Date: Sun, 22 Jun 2025 10:46:13 +0900 Subject: [PATCH 3/5] solve(w13): 230. Kth Smallest Element in a BST --- kth-smallest-element-in-a-bst/seungriyou.py | 92 +++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 kth-smallest-element-in-a-bst/seungriyou.py diff --git a/kth-smallest-element-in-a-bst/seungriyou.py b/kth-smallest-element-in-a-bst/seungriyou.py new file mode 100644 index 000000000..2edba5294 --- /dev/null +++ b/kth-smallest-element-in-a-bst/seungriyou.py @@ -0,0 +1,92 @@ +# https://leetcode.com/problems/kth-smallest-element-in-a-bst/ + +from typing import Optional + +# Definition for a binary tree node. +class TreeNode: + def __init__(self, val=0, left=None, right=None): + self.val = val + self.left = left + self.right = right + +class Solution: + def kthSmallest_recur(self, root: Optional[TreeNode], k: int) -> int: + """ + [Complexity] + - TC: O(k) + - SC: O(height) (call stack) + + [Approach] + BST를 inorder로 순회하면 오름차순으로 node를 방문할 수 있다. (recursive) + 각 호출에서 cnt를 세며 k와 같을 때 res 값을 기록한다. + """ + cnt, res = 0, None + + def inorder(node): + nonlocal cnt, res + + # base condition + if not node or res: + return + + # recur + inorder(node.left) + cnt += 1 + if cnt == k: + res = node.val + inorder(node.right) + + inorder(root) + + return res + + def kthSmallest_recur2(self, root: Optional[TreeNode], k: int) -> int: + """ + [Complexity] + - TC: O(k) + - SC: O(height) (call stack) + + [Approach] + 이전 recursive 풀이를 generator 방식으로 바꿀 수 있다. (yield from으로 recursion 구현) + """ + + def inorder(node): + if node: + yield from inorder(node.left) + yield node + yield from inorder(node.right) + + for i, node in enumerate(inorder(root), start=1): + if i == k: + return node.val + + def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: + """ + [Complexity] + - TC: O(k) + - SC: O(height) (stack에는 최대 height 개의 node가 들어감) + + [Approach] + BST의 inorder 순회를 stack을 이용하여 iterative 하게 풀이할 수 있다. + """ + cnt, stack = 0, [] + + # root에서부터 left child를 stack에 넣기 + while root: + stack.append(root) + root = root.left + + # leaf left child 부터 stack에서 pop + while stack: + node = stack.pop() + cnt += 1 + + if cnt == k: + return node.val + + # 현재 node의 right child가 있다면 stack에 넣고 + right = node.right + while right: + # right child에서부터 left child를 stack에 넣기 + stack.append(right) + right = right.left From b474b7d2a18cbb55c8b841a6a92f8f48ac1de572 Mon Sep 17 00:00:00 2001 From: seungriyou Date: Mon, 23 Jun 2025 21:44:54 +0900 Subject: [PATCH 4/5] solve(w13): 57. Insert Interval --- insert-interval/seungriyou.py | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 insert-interval/seungriyou.py diff --git a/insert-interval/seungriyou.py b/insert-interval/seungriyou.py new file mode 100644 index 000000000..8b659f1df --- /dev/null +++ b/insert-interval/seungriyou.py @@ -0,0 +1,41 @@ +# https://leetcode.com/problems/insert-interval/ + +from typing import List + +class Solution: + def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]: + """ + [Complexity] + - TC: O(n) + - SC: O(n) + + [Approach] + intervals의 각 interval에 대해 다음의 케이스로 나눠볼 수 있다. + 1) left에 해당하는 interval: left에 추가 + 2) right에 해당하는 interval: right에 추가 + 3) newInterval과 겹치는 interval: ns & ne 업데이트 (newInterval 확장) + """ + ns, ne = newInterval + + # left: end < ns + # right: start > ne + left, right = [], [] + + for s, e in intervals: + # 1) left에 해당하는 interval이라면, left에 추가 + if e < ns: + left.append([s, e]) + + # 2) right에 해당하는 interval이라면, right에 추가 + elif s > ne: + right.append([s, e]) + + # 3) newInterval과 겹치는 interval이라면, ns & ne 업데이트 + else: + ns = min(ns, s) + ne = max(ne, e) + + # left.append([ns, ne]) + # left.extend(right) + # return left + return left + [[ns, ne]] + right From 80c82a82a07594f3ba09790e033b48c89fd621c7 Mon Sep 17 00:00:00 2001 From: seungriyou Date: Tue, 24 Jun 2025 23:19:29 +0900 Subject: [PATCH 5/5] solve(w13): 295. Find Median from Data Stream --- find-median-from-data-stream/seungriyou.py | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 find-median-from-data-stream/seungriyou.py diff --git a/find-median-from-data-stream/seungriyou.py b/find-median-from-data-stream/seungriyou.py new file mode 100644 index 000000000..a0354cf27 --- /dev/null +++ b/find-median-from-data-stream/seungriyou.py @@ -0,0 +1,41 @@ +# https://leetcode.com/problems/find-median-from-data-stream/ + +import heapq + +class MedianFinder: + """ + [Time Complexity] + - addNum(): O(logn) (heappush / heappop -> 힙 속성 유지 위해 트리 높이만큼 swap => sift-up / sift-down) + - findMedian(): O(1) + + [Approach] + findMedian을 O(1)에 수행하기 위해서는 addNum을 할 때마다 데이터를 작은 부분 / 큰 부분으로 절반씩 나누어서 유지해야 한다. + 이때, 가능한 케이스별 median을 구하는 방법은 다음과 같다. + - 두 절반의 길이가 같다면 median = ((작은 부분의 가장 큰 값) + (큰 부분의 가장 작은 값)) / 2 + - 두 절반의 길이가 다르다면 (큰 부분의 길이가 작은 부분의 길이보다 1 큰 경우라고 가정) median = (큰 부분의 가장 작은 값) + 따라서 작은 부분 / 큰 부분을 각각 max heap / min heap으로 관리하며, addNum 할 때마다 다음은 동작을 수행한다. + - 두 절반의 길이가 같다면, 작은 부분에 push -> pop 한 결과를 큰 부분에 push + - 두 절반의 길이가 다르다면, 큰 부분에 push -> pop 한 결과를 작은 부분에 push + (파이썬에서 max heap을 사용하기 위해서는 min heap에 부호 반전인 수를 넣음으로써 구현하는 것에 유의한다!) + """ + + def __init__(self): + self.lo = [] # 절반 중 작은 부분 + self.hi = [] # 절반 중 큰 부분 + + def addNum(self, num: int) -> None: + if len(self.lo) == len(self.hi): + heapq.heappush(self.hi, -heapq.heappushpop(self.lo, -num)) # heappushpop: heap을 한 번만 + else: + heapq.heappush(self.lo, -heapq.heappushpop(self.hi, num)) + + def findMedian(self) -> float: + if len(self.lo) == len(self.hi): + return (-self.lo[0] + self.hi[0]) / 2 + else: + return self.hi[0] + +# Your MedianFinder object will be instantiated and called as such: +# obj = MedianFinder() +# obj.addNum(num) +# param_2 = obj.findMedian()