From 6913e2ad34a14cc01c2386407a9c1ec3964c7c4d Mon Sep 17 00:00:00 2001 From: Nayeon Date: Sun, 9 Feb 2025 10:30:04 +0900 Subject: [PATCH 1/9] chore: add placeholder for leetcode 226 (invert binary tree) --- invert-binary-tree/KwonNayeon.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 invert-binary-tree/KwonNayeon.py diff --git a/invert-binary-tree/KwonNayeon.py b/invert-binary-tree/KwonNayeon.py new file mode 100644 index 000000000..0efe091c3 --- /dev/null +++ b/invert-binary-tree/KwonNayeon.py @@ -0,0 +1,14 @@ +""" +Constraints: +- + +Time Complexity: +- + +Space Complexity: +- + +풀이방법: +1. +""" + From d1bded373eaa8fa26b996f307f5b7265d2bd3b10 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Mon, 10 Feb 2025 18:32:23 +0900 Subject: [PATCH 2/9] solve: Invert Binary Tree --- invert-binary-tree/KwonNayeon.py | 45 +++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/invert-binary-tree/KwonNayeon.py b/invert-binary-tree/KwonNayeon.py index 0efe091c3..59da0330b 100644 --- a/invert-binary-tree/KwonNayeon.py +++ b/invert-binary-tree/KwonNayeon.py @@ -1,14 +1,47 @@ """ Constraints: -- +- The number of nodes in the tree is in the range [0, 100]. +- -100 <= Node.val <= 100 -Time Complexity: -- +Time Complexity: +- O(n): 각 노드를 한 번씩 방문함 -Space Complexity: -- +Space Complexity: +- O(w): w는 트리의 최대 너비(width) 풀이방법: -1. +1. 큐를 사용한 BFS(너비 우선 탐색) +2. FIFO(First In First Out)로 노드를 처리함 +3. 각 노드를 방문할 때마다: + - 왼쪽과 오른쪽 자식 노드의 위치를 교환 + - 교환된 자식 노드들을 큐에 추가하여 다음 노드를 처리함 """ +# 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 +from collections import deque + +class Solution: + def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + if not root: + return None + + queue = deque([root]) + + while queue: + node = queue.popleft() + + node.left, node.right = node.right, node.left + + if node.left: + queue.append(node.left) + if node.right: + queue.append(node.right) + + return root + + From 87285cf0c1e12c5a49e86b5059e62806de265667 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Tue, 11 Feb 2025 16:50:09 +0900 Subject: [PATCH 3/9] solve: Search in Rotated Sorted Array --- search-in-rotated-sorted-array/KwonNayeon.py | 55 ++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 search-in-rotated-sorted-array/KwonNayeon.py diff --git a/search-in-rotated-sorted-array/KwonNayeon.py b/search-in-rotated-sorted-array/KwonNayeon.py new file mode 100644 index 000000000..1c289b3a3 --- /dev/null +++ b/search-in-rotated-sorted-array/KwonNayeon.py @@ -0,0 +1,55 @@ +""" +Constraints: +- 1 <= nums.length <= 5000 +- -10^4 <= nums[i] <= 10^4 +- All values of nums are unique. +- nums is an ascending array that is possibly rotated. +- -10^4 <= target <= 10^4 + +Time Complexity: O(log n) +- Binary Search -> 매 단계마다 탐색 범위가 절반으로 줄어듦 + +Space Complexity: O(1) +- 추가 공간을 사용하지 않음 + +풀이방법: +1. Binary Search + - left와 right 포인터로 탐색 범위 지정 + - mid가 target인지 먼저 확인 + +2. 정렬된 부분 찾기 + - mid를 기준으로 왼쪽이 정렬되어 있는지 확인 + - 정렬된 부분에서 target이 존재할 수 있는 범위를 파악 + +3. Target 위치 탐색 + - 왼쪽이 정렬되어 있고 target이 그 범위 안에 있다면 오른쪽 범위를 줄임 + - 그렇지 않다면 왼쪽 범위를 늘림 + - 반대의 경우도 동일한 방법 적용 + +4. Target을 찾지 못한 경우 -1을 반환함 +""" +class Solution: + def search(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) - 1 + + while left <= right: + mid = (left + right) // 2 + + if nums[mid] == target: + return mid + + if nums[left] <= nums[mid]: + if nums[left] <= target <= nums[mid]: + right = mid - 1 + else: + left = mid + 1 + + else: + if nums[mid] < target <= nums[right]: + left = mid + 1 + else: + right = mid - 1 + + return -1 + From 46c7a69c70f4f79dc874e614d13fbc700552dae0 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Wed, 12 Feb 2025 15:19:29 +0900 Subject: [PATCH 4/9] solve: Course Schedule --- course-schedule/KwonNayeon.py | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 course-schedule/KwonNayeon.py diff --git a/course-schedule/KwonNayeon.py b/course-schedule/KwonNayeon.py new file mode 100644 index 000000000..fc41490e0 --- /dev/null +++ b/course-schedule/KwonNayeon.py @@ -0,0 +1,59 @@ +""" +Constraints: +- 1 <= numCourses <= 2000 +- 0 <= prerequisites.length <= 5000 +- prerequisites[i].length == 2 +- 0 <= ai, bi < numCourses +- All the pairs prerequisites[i] are unique. + + +Time Complexity: O(N + P) +- N: numCourses, P: prerequisites의 길이 + +Space Complexity: O(N + P) +- 세트의 메모리 사용량이 N과 비례하고 인접 리스트의 크기가 P + +풀이방법: +1. prerequisites을 directed graph로 변환 + - 각 코스별로 선수과목의 리스트를 저장함 + +2. DFS를 사용하여 cycle 존재 여부 확인 + - visited 배열: 이미 확인이 완료된 노드 체크 + - path 배열: 현재 DFS 경로에서 방문한 노드 체크 + +3. cycle이 발견되면 false, 그렇지 않으면 true 반환 + - 현재 경로에서 이미 방문한 노드를 다시 만나면 cycle 있음 + - 모든 노드 방문이 가능하면 cycle 없음 +""" +class Solution: + def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: + graph = [[] for _ in range(numCourses)] + for course, prereq in prerequisites: + graph[course].append(prereq) + + visited = [False] * numCourses + path = [False] * numCourses + + def dfs(course): + if path[course]: + return False + if visited[course]: + return True + + path[course] = True + + for prereq in graph[course]: + if not dfs(prereq): + return False + + path[course] = False + visited[course] = True + + return True + + for course in range(numCourses): + if not dfs(course): + return False + + return True + From 2ef46df53fb5ec38346c35e3a8d9501e97de4203 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Wed, 12 Feb 2025 15:20:55 +0900 Subject: [PATCH 5/9] chore: Remove newlines --- course-schedule/KwonNayeon.py | 1 - 1 file changed, 1 deletion(-) diff --git a/course-schedule/KwonNayeon.py b/course-schedule/KwonNayeon.py index fc41490e0..e67f69889 100644 --- a/course-schedule/KwonNayeon.py +++ b/course-schedule/KwonNayeon.py @@ -6,7 +6,6 @@ - 0 <= ai, bi < numCourses - All the pairs prerequisites[i] are unique. - Time Complexity: O(N + P) - N: numCourses, P: prerequisites의 길이 From d58c8864ff63d886393d02fceee065f3a0f68410 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Wed, 12 Feb 2025 17:10:41 +0900 Subject: [PATCH 6/9] add: solution with dfs and recursive --- invert-binary-tree/KwonNayeon.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/invert-binary-tree/KwonNayeon.py b/invert-binary-tree/KwonNayeon.py index 59da0330b..39e02f857 100644 --- a/invert-binary-tree/KwonNayeon.py +++ b/invert-binary-tree/KwonNayeon.py @@ -25,6 +25,7 @@ # self.right = right from collections import deque +# Solution 1 (BFS 활용) class Solution: def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: if not root: @@ -44,4 +45,15 @@ def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: return root +# Solution 2 (DFS와 재귀 활용) +class Solution: + def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + if not root: + return None + root.left, root.right = root.right, root.left + + self.invertTree(root.left) + self.invertTree(root.right) + + return root From b175e3118296e4a41eda19817532521e5c9020a2 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Thu, 13 Feb 2025 17:59:12 +0900 Subject: [PATCH 7/9] solve: Jump Game --- jump-game/KwonNayeon.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 jump-game/KwonNayeon.py diff --git a/jump-game/KwonNayeon.py b/jump-game/KwonNayeon.py new file mode 100644 index 000000000..26728ce43 --- /dev/null +++ b/jump-game/KwonNayeon.py @@ -0,0 +1,32 @@ +""" +Constraints: +- 1 <= nums.length <= 10^4 +- 0 <= nums[i] <= 10^5 + +Time Complexity: O(n) +- n은 배열의 길이만큼 한 번 순회 + +Space Complexity: O(1) +- 추가 공간 사용 없음 + +풀이방법: +1. max_reach 변수로 현재까지 도달 가능한 최대 거리 저장 +2. 배열을 순회하면서: + - 현재 위치가 max_reach보다 크면 도달 불가능 + - max_reach를 현재 위치에서 점프 가능한 거리와 비교해 업데이트 + - max_reach가 마지막 인덱스보다 크면 도달 가능 +""" +class Solution: + def canJump(self, nums: List[int]) -> bool: + max_reach = nums[0] + + for i in range(len(nums)): + if i > max_reach: + return False + + max_reach = max(max_reach, i + nums[i]) + + if max_reach >= len(nums) - 1: + return True + + return True From 862ff81e5c46c7f095a793889b4640024a900548 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Fri, 14 Feb 2025 17:21:23 +0900 Subject: [PATCH 8/9] docs: add notes - Solution 2 (Invert binary tree) & SC (Course schecule) --- course-schedule/KwonNayeon.py | 5 ++-- invert-binary-tree/KwonNayeon.py | 24 ++++++++++++++++---- merge-k-sorted-lists/KwonNayeon.py | 18 +++++++++++++++ search-in-rotated-sorted-array/KwonNayeon.py | 3 --- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 merge-k-sorted-lists/KwonNayeon.py diff --git a/course-schedule/KwonNayeon.py b/course-schedule/KwonNayeon.py index e67f69889..51ffb0697 100644 --- a/course-schedule/KwonNayeon.py +++ b/course-schedule/KwonNayeon.py @@ -9,17 +9,16 @@ Time Complexity: O(N + P) - N: numCourses, P: prerequisites의 길이 -Space Complexity: O(N + P) +Space Complexity: O(N + P) - 세트의 메모리 사용량이 N과 비례하고 인접 리스트의 크기가 P +- 재귀 호출 스택의 깊이는 최악의 경우 O(N) 풀이방법: 1. prerequisites을 directed graph로 변환 - 각 코스별로 선수과목의 리스트를 저장함 - 2. DFS를 사용하여 cycle 존재 여부 확인 - visited 배열: 이미 확인이 완료된 노드 체크 - path 배열: 현재 DFS 경로에서 방문한 노드 체크 - 3. cycle이 발견되면 false, 그렇지 않으면 true 반환 - 현재 경로에서 이미 방문한 노드를 다시 만나면 cycle 있음 - 모든 노드 방문이 가능하면 cycle 없음 diff --git a/invert-binary-tree/KwonNayeon.py b/invert-binary-tree/KwonNayeon.py index 39e02f857..31987ef75 100644 --- a/invert-binary-tree/KwonNayeon.py +++ b/invert-binary-tree/KwonNayeon.py @@ -3,11 +3,12 @@ - The number of nodes in the tree is in the range [0, 100]. - -100 <= Node.val <= 100 -Time Complexity: -- O(n): 각 노드를 한 번씩 방문함 + +Time Complexity: O(n) +- 각 노드를 한 번씩 방문함 -Space Complexity: -- O(w): w는 트리의 최대 너비(width) +Space Complexity: O(w) +- w는 트리의 최대 너비(width) 풀이방법: 1. 큐를 사용한 BFS(너비 우선 탐색) @@ -15,8 +16,21 @@ 3. 각 노드를 방문할 때마다: - 왼쪽과 오른쪽 자식 노드의 위치를 교환 - 교환된 자식 노드들을 큐에 추가하여 다음 노드를 처리함 -""" + +Time Complexity: O(n) +- 각 노드를 한 번씩 방문함 + +Space Complexity: O(h) +- h는 트리의 높이, 재귀 호출 스택의 최대 깊이 + +풀이방법: +1. DFS(깊이 우선 탐색)와 재귀를 활용 +2. 각 노드에서: + - 왼쪽과 오른쪽 자식 노드의 위치를 교환 + - 재귀적으로 왼쪽, 오른쪽 서브트리에 대해 같은 과정 반복 +3. Base case: root가 None이면 None 반환 +""" # Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): diff --git a/merge-k-sorted-lists/KwonNayeon.py b/merge-k-sorted-lists/KwonNayeon.py new file mode 100644 index 000000000..752d3e59b --- /dev/null +++ b/merge-k-sorted-lists/KwonNayeon.py @@ -0,0 +1,18 @@ +""" +Constraints: +- k == lists.length +- 0 <= k <= 10^4 +- 0 <= lists[i].length <= 500 +- -10^4 <= lists[i][j] <= 10^4 +- lists[i] is sorted in ascending order. +- The sum of lists[i].length will not exceed 10^4 + +Time Complexity: +- + +Space Complexity: +- + +풀이방법: +1. +""" diff --git a/search-in-rotated-sorted-array/KwonNayeon.py b/search-in-rotated-sorted-array/KwonNayeon.py index 1c289b3a3..71fc53c0e 100644 --- a/search-in-rotated-sorted-array/KwonNayeon.py +++ b/search-in-rotated-sorted-array/KwonNayeon.py @@ -16,16 +16,13 @@ 1. Binary Search - left와 right 포인터로 탐색 범위 지정 - mid가 target인지 먼저 확인 - 2. 정렬된 부분 찾기 - mid를 기준으로 왼쪽이 정렬되어 있는지 확인 - 정렬된 부분에서 target이 존재할 수 있는 범위를 파악 - 3. Target 위치 탐색 - 왼쪽이 정렬되어 있고 target이 그 범위 안에 있다면 오른쪽 범위를 줄임 - 그렇지 않다면 왼쪽 범위를 늘림 - 반대의 경우도 동일한 방법 적용 - 4. Target을 찾지 못한 경우 -1을 반환함 """ class Solution: From b22c9edc500e243c681b020bac7007874d7493e1 Mon Sep 17 00:00:00 2001 From: Nayeon Date: Fri, 14 Feb 2025 23:20:45 +0900 Subject: [PATCH 9/9] solve: Merge K Sorted Lists --- merge-k-sorted-lists/KwonNayeon.py | 41 ++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/merge-k-sorted-lists/KwonNayeon.py b/merge-k-sorted-lists/KwonNayeon.py index 752d3e59b..3f518940e 100644 --- a/merge-k-sorted-lists/KwonNayeon.py +++ b/merge-k-sorted-lists/KwonNayeon.py @@ -7,12 +7,43 @@ - lists[i] is sorted in ascending order. - The sum of lists[i].length will not exceed 10^4 -Time Complexity: -- +Time Complexity: O(N log k) +- N은 모든 노드의 총 개수, k는 연결 리스트의 개수 +- 힙 연산에 log k 시간이 걸리고, 이를 N번 수행함 -Space Complexity: -- +Space Complexity: O(k) +- 힙에는 항상 k개의 노드만 저장됨 풀이방법: -1. +1. 최소 힙을 사용하여 k개의 정렬된 리스트를 효율적으로 병합하는 알고리즘 +2. 각 리스트의 첫 번째 노드를 힙에 넣고 시작함 +3. 힙에서 가장 작은 값을 가진 노드를 꺼내서 결과 리스트에 추가 +4. 꺼낸 노드의 다음 노드를 다시 힙에 넣음 +5. 이 과정을 힙이 빌 때까지 반복함 + +Note: 이 문제는 풀기 어려워서 풀이를 보고 공부했습니다. 복습 필수 """ +# Definition for singly-linked list. +# 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]: + min_heap = [] + + for i, l in enumerate(lists): + if l: + heapq.heappush(min_heap, (l.val, i, l)) + + head = point = ListNode(0) + + while min_heap: + val, i, node = heapq.heappop(min_heap) + point.next = node + point = point.next + + if node.next: + heapq.heappush(min_heap, (node.next.val, i, node.next)) + + return head.next