From 7944537b7eeba68d1c0619142cfbf8d38c866720 Mon Sep 17 00:00:00 2001 From: EGON Date: Sun, 10 Nov 2024 03:59:31 +0900 Subject: [PATCH 1/5] feat: solve #231 with python --- meeting-rooms/EGON.py | 66 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 meeting-rooms/EGON.py diff --git a/meeting-rooms/EGON.py b/meeting-rooms/EGON.py new file mode 100644 index 000000000..81604f230 --- /dev/null +++ b/meeting-rooms/EGON.py @@ -0,0 +1,66 @@ +from typing import List +from unittest import TestCase, main + + +# Definition of Interval: +class Interval(object): + def __init__(self, start, end): + self.start = start + self.end = end + + +class Solution: + def canAttendMeetings(self, intervals: List[Interval]) -> bool: + return self.solve_sort_stack(intervals) + + """ + LintCode 로그인이 안되어서 hhttps://neetcode.io/problems/meeting-schedule 에서 실행시키고 통과만 확인했습니다. + + Runtime: ? ms (Beats ?%) + Time Complexity: O(n log n) + - intervals 정렬에 O(n log n) + - intervals 조회하며 stack의 마지막 값의 end와 현재 interval의 start를 비교하는데 O(n) + > O(n log n) + O(n) ~= O(n log n) + + Memory: ? MB (Beats ?%) + Space Complexity: O(n) + - intervals 메모리를 그대로 사용하면서 정렬했으므로 O(1) + - stack의 크기는 최대 intervals와 같아질 수 있으므로 O(n) + """ + + def solve_sort_stack(self, intervals: List[Interval]) -> bool: + intervals.sort(key=lambda x: x.start) + + stack: List[Interval] = [] + for interval in intervals: + if not stack: + stack.append(interval) + continue + + if stack[-1].end > interval.start: + return False + else: + stack.append(interval) + + return True + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + intervals = [Interval(0,30), Interval(5,10), Interval(15,20)] + output = False + self.assertEqual(Solution().canAttendMeetings(intervals), output) + + def test_2(self): + intervals = [Interval(5, 8), Interval(9,15)] + output = False + self.assertEqual(Solution().canAttendMeetings(intervals), output) + + def test_3(self): + intervals = [Interval(0, 1), Interval(1, 2)] + output = False + self.assertEqual(Solution().canAttendMeetings(intervals), output) + + +if __name__ == '__main__': + main() From 205f2a5561acf5d341a525cfd05e9f4cab00982a Mon Sep 17 00:00:00 2001 From: EGON Date: Sun, 10 Nov 2024 03:59:45 +0900 Subject: [PATCH 2/5] feat: solve #249 with python --- .../EGON.py | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 lowest-common-ancestor-of-a-binary-search-tree/EGON.py diff --git a/lowest-common-ancestor-of-a-binary-search-tree/EGON.py b/lowest-common-ancestor-of-a-binary-search-tree/EGON.py new file mode 100644 index 000000000..2efa9d37b --- /dev/null +++ b/lowest-common-ancestor-of-a-binary-search-tree/EGON.py @@ -0,0 +1,106 @@ +from collections import deque +from unittest import TestCase, main + + +# Definition of TreeNode: +class TreeNode: + def __init__(self, x): + self.val = x + self.left = None + self.right = None + + +class Solution: + def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: + return self.solve_bfs(root, p, q) + + """ + Runtime: 50 ms (Beats 81.68%) + Time Complexity:` + - bfs를 이용해 ancetor와 nodes를 초기화 하는데 트리의 모든 p와 q를 포함할 때까지 모든 node를 조회하는데, O(n) + - p로 부터 부모를 따라 올라가는데, 트리의 모든 node가 편향적으로 연결된 경우 최대 O(n), upper bound + - q로 부터 부모를 따라 올라가는데, 단, 위 p의 추적 path와 겹치지 않는 곳만 올라가므로, 총합이 O(n) + > O(n) + (O(P) + O(Q)) = O(n) + O(n) ~= O(n) + + Memory: 21.20 MB (Beats 14.40%) + Space Complexity: O(n) + - p, q가 트리의 리프노드인 경우 dq의 크기는 O(n), upper bound + - p_ancestors와 q_anscestor의 크기는 합쳐서 O(n) + > O(n) + O(n) ~= O(n) + """ + def solve_bfs(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode: + dq = deque([root]) + ancestor = {root.val: root.val} + nodes = {root.val: root} + while dq: + if p.val in ancestor and q.val in ancestor: + break + + curr_node = dq.popleft() + if curr_node.left: + ancestor[curr_node.left.val] = curr_node.val + dq.append(curr_node.left) + nodes[curr_node.left.val] = curr_node.left + if curr_node.right: + ancestor[curr_node.right.val] = curr_node.val + dq.append(curr_node.right) + nodes[curr_node.right.val] = curr_node.right + + p_val = p.val + p_ancestors = set() + p_ancestors.add(root.val) + while p_val in ancestor and p_val != root.val: + p_ancestors.add(p_val) + p_ancestors.add(ancestor[p_val]) + p_val = ancestor[p_val] + + q_val = q.val + q_ancestors = set() + q_ancestors.add(q_val) + while q_val in ancestor and q_val not in p_ancestors: + q_ancestors.add(q_val) + q_ancestors.add(ancestor[q_val]) + q_val = ancestor[q_val] + + common_ancestor = p_ancestors & q_ancestors + if common_ancestor: + return nodes[common_ancestor.pop()] + else: + return root + + +class _LeetCodeTestCases(TestCase): + + def test_1(self): + root = TreeNode(5) + node1 = TreeNode(3) + node2 = TreeNode(6) + node3 = TreeNode(2) + node4 = TreeNode(4) + node5 = TreeNode(1) + + root.left = node1 + root.right = node2 + node1.left = node3 + node1.right = node4 + node3.left = node5 + + p = node5 + q = node1 + output = root + self.assertEqual(Solution().lowestCommonAncestor(root, p, q), output) + + def test_2(self): + root = TreeNode(2) + node1 = TreeNode(1) + + root.left = node1 + + p = TreeNode(2) + q = TreeNode(1) + output = root + self.assertEqual(Solution().lowestCommonAncestor(root, p, q), output) + + +if __name__ == '__main__': + main() From 7643d32e0b7614c75d01f6847487642fdf49936b Mon Sep 17 00:00:00 2001 From: EGON Date: Sun, 10 Nov 2024 03:59:59 +0900 Subject: [PATCH 3/5] feat: solve #264 with python --- house-robber/EGON.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 house-robber/EGON.py diff --git a/house-robber/EGON.py b/house-robber/EGON.py new file mode 100644 index 000000000..e6fc8db52 --- /dev/null +++ b/house-robber/EGON.py @@ -0,0 +1,42 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def rob(self, nums: List[int]) -> int: + return self.solve_dp(nums) + + """ + Runtime: 0 ms (Beats 100.00%) + Time Complexity: O(n) + - nums 배열을 조회하며 dp 배열을 갱신하므로 O(n) + - 2항에 대한 max 연산을 사용하므로 * O(2) + > O(2 * n) ~= O(n) + + Memory: 16.62 MB (Beats 24.05%) + Space Complexity: O(n) + > 길이가 n인 dp 배열을 사용하므로 O(n) + """ + + def solve_dp(self, nums: List[int]) -> int: + if len(nums) <= 2: + return max(nums) + + dp = [0] * len(nums) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + for i in range(2, len(nums)): + dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) + + return dp[-1] + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + nums = [2,1,1,2] + output = 4 + self.assertEqual(Solution().rob(nums), output) + + +if __name__ == '__main__': + main() From c5d1d4d7d6fe62bf0fafbb2bc2cf396f5ec6153c Mon Sep 17 00:00:00 2001 From: EGON Date: Sun, 10 Nov 2024 04:00:12 +0900 Subject: [PATCH 4/5] feat: solve #279 with python --- non-overlapping-intervals/EGON.py | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 non-overlapping-intervals/EGON.py diff --git a/non-overlapping-intervals/EGON.py b/non-overlapping-intervals/EGON.py new file mode 100644 index 000000000..dac68fe2a --- /dev/null +++ b/non-overlapping-intervals/EGON.py @@ -0,0 +1,45 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: + return self.solve_stack(intervals) + + """ + LintCode 로그인이 안되어서 hhttps://neetcode.io/problems/meeting-schedule 에서 실행시키고 통과만 확인했습니다. + + Runtime: 66 ms (Beats 85.10%) + Time Complexity: O(n log n) + - intervals를 정렬하는데 O(n log n) + - intervals를 조회하며 result stack을 갱신하는데 O(n) + - 2항에 대한 or 연산 및 append 메서드만 쓰므로 * O(1) + > O(n log n) + O(n) ~= O(n log n) + Memory: 50.98 MB (Beats 74.30%) + Space Complexity: O(n) + - intervals 정렬도 기존 intervals를 사용하므로 O(1) + - result의 크기가 최대 interval과 같아질 수 있으므로 O(n) + > O(1) + O(n) ~= O(n) + """ + def solve_stack(self, intervals: List[List[int]]) -> int: + if not intervals: + return 0 + + intervals.sort(key=lambda x: x[1]) + result = [] + for interval in intervals: + if not result or interval[0] >= result[-1][1]: + result.append(interval) + + return len(intervals) - len(result) + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + intervals = [[1,2],[2,3],[3,4],[1,3]] + output = 1 + self.assertEqual(Solution().eraseOverlapIntervals(intervals), output) + + +if __name__ == '__main__': + main() From 48e575407cff6d3863a9a94f43a508f3244a6ae9 Mon Sep 17 00:00:00 2001 From: EGON Date: Sun, 10 Nov 2024 04:00:25 +0900 Subject: [PATCH 5/5] feat: solve #289 with python --- find-median-from-data-stream/EGON.py | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 find-median-from-data-stream/EGON.py diff --git a/find-median-from-data-stream/EGON.py b/find-median-from-data-stream/EGON.py new file mode 100644 index 000000000..f4315bf3d --- /dev/null +++ b/find-median-from-data-stream/EGON.py @@ -0,0 +1,67 @@ +from heapq import heappush, heappop +from unittest import TestCase, main + + +class MedianFinder: + """ + Runtime: 137 ms (Beats 56.16%) + Time Complexity: + 1) addNum + - 최악의 경우 heappush + (heappop + heappush) + (heappop + heapppush) 가 발생할 수 있으므로 O(5 * log n) + > O(5 * log n) ~= O(log n) + 2) findMedian + > heap의 루트 값을 가지고 사칙연산만 하므로 O(1) + + Memory: 39.94 MB (Beats 5.85%) + Space Complexity: O(n) + - max_heap은 최대 n // 2 개 혹은 n // 2 + 1개의 원소를 가지므로 O(n / 2 + 1), upper bound + - min_heap은 최대 n // 2개의 원소를 가지므로 O(n / 2) + > O(n / 2 + 1) + O(n / 2) ~= O(n) + O(n) ~= O(n) + """ + + def __init__(self): + self.max_heap = [] + self.min_heap = [] + + def addNum(self, num): + heappush(self.max_heap, -num) + if self.min_heap and (-self.max_heap[0] > self.min_heap[0]): + heappush(self.min_heap, -heappop(self.max_heap)) + + if len(self.max_heap) > len(self.min_heap) + 1: + heappush(self.min_heap, -heappop(self.max_heap)) + elif len(self.max_heap) < len(self.min_heap): + heappush(self.max_heap, -heappop(self.min_heap)) + + def findMedian(self): + if self.max_heap and self.min_heap: + if len(self.max_heap) == len(self.min_heap): + return ((-self.max_heap[0]) + self.min_heap[0]) / 2 + else: + return -self.max_heap[0] + elif self.min_heap and not self.max_heap: + return self.min_heap[0] + elif not self.min_heap and self.max_heap: + return -self.max_heap[0] + else: + return 0.0 + + +class _LeetCodeTestCases(TestCase): + + def test_1(self): + medianFinder = MedianFinder() + medianFinder.addNum(-1) + self.assertEqual(medianFinder.findMedian(), -1.0) + medianFinder.addNum(-2) + self.assertEqual(medianFinder.findMedian(), -1.5) + medianFinder.addNum(-3) + self.assertEqual(medianFinder.findMedian(), -2.0) + medianFinder.addNum(-4) + self.assertEqual(medianFinder.findMedian(), -2.5) + medianFinder.addNum(-5) + self.assertEqual(medianFinder.findMedian(), -3.0) + + +if __name__ == '__main__': + main()