diff --git a/course-schedule/EGON.py b/course-schedule/EGON.py new file mode 100644 index 000000000..9f1bd04fa --- /dev/null +++ b/course-schedule/EGON.py @@ -0,0 +1,58 @@ +from collections import deque +from typing import List +from unittest import TestCase, main + + +class Solution: + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: + return self.solve_topological_sort(numCourses, prerequisites) + + """ + Runtime: 1 ms (Beats 100.00%) + Time Complexity: o(c + p) + - graph 및 rank 갱신에 prerequisites의 길이 p만큼 조회하는데 O(p) + - queue의 초기 노드 삽입에 numCourses만큼 조회하는데 O(c) + - queue에서 위상 정렬로 탐색하는데 모든 노드와 간선을 조회하는데 O(c + p) + > O(p) + O(c) + O(c + p) ~= o(c + p) + + Memory: 17.85 MB (Beats 99.94%) + Space Complexity: O(c) + - graph 변수 사용에 O(c + p) + - rank 변수 사용에 O(c) + - queue 변수 사용에서 최대 크기는 graph의 크기와 같으므로 O(c) + > O(c + p) + O(c) + O(c) ~= O(c + p) + """ + def solve_topological_sort(self, numCourses: int, prerequisites: List[List[int]]) -> bool: + graph = {i: [] for i in range(numCourses)} + rank = [0] * numCourses + for u, v in prerequisites: + graph[v].append(u) + rank[u] += 1 + + queue = deque() + for i in range(numCourses): + if rank[i] == 0: + queue.append(i) + + count = 0 + while queue: + node = queue.popleft() + count += 1 + for neighbor in graph[node]: + rank[neighbor] -= 1 + if rank[neighbor] == 0: + queue.append(neighbor) + + return count == numCourses + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + numCourses = 5 + prerequisites = [[1,4],[2,4],[3,1],[3,2]] + output = True + self.assertEqual(Solution.canFinish(Solution(), numCourses, prerequisites), output) + + +if __name__ == '__main__': + main() diff --git a/invert-binary-tree/EGON.py b/invert-binary-tree/EGON.py new file mode 100644 index 000000000..b49826895 --- /dev/null +++ b/invert-binary-tree/EGON.py @@ -0,0 +1,48 @@ +from typing import Optional +from unittest import TestCase, main + + +# 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 invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + return self.solve_dfs(root) + + """ + Runtime: 0 ms (Beats 100.00%) + Time Complexity: O(n) + > 트리의 모든 node를 방문하므로 O(n) + + Memory: 16.53 MB (Beats 25.95%) + Space Complexity: O(n) + > stack의 최대 크기는 트리의 최장 경로를 이루는 node의 갯수이고, 최악의 경우 트리의 한 쪽으로 모든 node가 이어져있는 경우이므로 O(n), upper bound + """ + def solve_dfs(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + if root is None: + return root + + stack = [root] + while stack: + curr_node = stack.pop() + curr_node.left, curr_node.right = curr_node.right, curr_node.left + if curr_node.left: + stack.append(curr_node.left) + if curr_node.right: + stack.append(curr_node.right) + + return root + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + return + + +if __name__ == '__main__': + main() diff --git a/jump-game/EGON.py b/jump-game/EGON.py new file mode 100644 index 000000000..a09030f29 --- /dev/null +++ b/jump-game/EGON.py @@ -0,0 +1,43 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def canJump(self, nums: List[int]) -> bool: + return self.solve_dp(nums) + + """ + Runtime: 3130 ms (Beats 11.42%) + Time Complexity: O(n * m) + - dp 배열 생성에 nums의 길이 n 만큼 조회하는데 O(n) + - 생성한 dp 배열을 조회하는데 O(n) + - dp[i]에서 점프하는 범위에 의해 * O(2 * m) + > O(n) + O(n) * O(2 * m) ~= O(n * m) + + Memory: 17.80 MB (Beats 72.54%) + Space Complexity: O(n) + > nums의 길이에 비례하는 dp 배열 하나만 사용, O(n) + """ + def solve_dp(self, nums: List[int]) -> bool: + dp = [True if i == 0 else False for i in range(len(nums))] + for i in range(len(nums)): + if dp[-1] is True: + return True + + if dp[i] is True: + for jump in range(nums[i] + 1): + if 0 <= i + jump < len(dp): + dp[i + jump] = True + + return dp[-1] + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + nums = [2, 3, 1, 1, 4] + output = True + self.assertEqual(Solution.canJump(Solution(), nums), output) + + +if __name__ == '__main__': + main() diff --git a/merge-k-sorted-lists/EGON.py b/merge-k-sorted-lists/EGON.py new file mode 100644 index 000000000..a4eaa9517 --- /dev/null +++ b/merge-k-sorted-lists/EGON.py @@ -0,0 +1,55 @@ +from heapq import heappush, heappop +from typing import List, Optional +from unittest import TestCase, main + + +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + +class Solution: + def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: + return self.solve_priority_queue(lists) + + """ + Runtime: 7 ms (Beats 100.00%) + Time Complexity: O(n * m) + - lists의 길이 k만큼 조회에 O(k) + - 힙의 크기가 최대 k이므로, heappush에 * O(log k) + - heap의 크기는 최대 k이므로, + - heappop하는데 O(k * log k) + - heappush하는데 lists를 이루는 list를 이루는 모든 원소들의 총 갯수를 n이라 하면, O(n * log k) + > O(k * log k) + O(k * log k) + O(n * log k) ~= O(max(k, n) * log k) = O(n * log k) + + Memory: 19.44 MB (Beats 58.42%) + Space Complexity: O(k) + > heap의 크기는 lists의 길이 k에 비례하므로, O(k) + """ + def solve_priority_queue(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: + root = result = ListNode(None) + heap = [] + + for i in range(len(lists)): + if lists[i]: + heappush(heap, (lists[i].val, i, lists[i])) + + while heap: + node = heappop(heap) + _, idx, result.next = node + + result = result.next + if result.next: + heappush(heap, (result.next.val, idx, result.next)) + + return root.next + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + self.assertEqual(True, True) + + +if __name__ == '__main__': + main() diff --git a/search-in-rotated-sorted-array/EGON.py b/search-in-rotated-sorted-array/EGON.py new file mode 100644 index 000000000..93a655a5b --- /dev/null +++ b/search-in-rotated-sorted-array/EGON.py @@ -0,0 +1,67 @@ +from typing import List +from unittest import TestCase, main + + +class Solution: + def search(self, nums: List[int], target: int) -> int: + return self.solve_binary_search(nums, target) + + """ + Runtime: 4 ms (Beats 100.00%) + Time Complexity: O(log n) + > nums를 이진탐색으로 조회하므로 O(log n) + + Memory: 17.03 MB (Beats 10.00%) + Space Complexity: O(1) + > index를 위한 정수형 변수만 사용하므로 O(1) + """ + def solve_binary_search(self, nums: List[int], target: int) -> int: + lo, hi = 0, len(nums) - 1 + while lo < hi: + mid = (lo + hi) // 2 + if nums[mid] == target: + return mid + + if nums[lo] <= nums[mid]: + if nums[lo] <= target <= nums[mid]: + hi = mid + else: + lo = mid + 1 + + else: + if nums[mid] <= target <= nums[hi]: + lo = mid + 1 + else: + hi = mid + + return lo if nums[lo] == target else -1 + + +class _LeetCodeTestCases(TestCase): + def test_1(self): + nums = [4,5,6,7,0,1,2] + target = 0 + output = 4 + self.assertEqual(Solution.search(Solution(), nums, target), output) + + def test_2(self): + nums = [4,5,6,7,0,1,2] + target = 3 + output = -1 + self.assertEqual(Solution.search(Solution(), nums, target), output) + + def test_3(self): + nums = [1] + target = 0 + output = -1 + self.assertEqual(Solution.search(Solution(), nums, target), output) + + def test_4(self): + nums = [3, 1] + target = 1 + output = 1 + self.assertEqual(Solution.search(Solution(), nums, target), output) + + +if __name__ == '__main__': + main()