Skip to content
Merged
57 changes: 57 additions & 0 deletions course-schedule/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 재귀 호출 스택의 깊이까지 언급해주면 더 좋을 것 같아요 :)

- 재귀 호출 스택의 깊이는 최악의 경우 O(N)

풀이방법:
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

73 changes: 73 additions & 0 deletions invert-binary-tree/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Constraints:
- The number of nodes in the tree is in the range [0, 100].
- -100 <= Node.val <= 100

<Solution 1>
Time Complexity: O(n)
- 각 노드를 한 번씩 방문함

Space Complexity: O(w)
- w는 트리의 최대 너비(width)

풀이방법:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BFS 풀이 방법 좋네요 :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@obzva 님 리뷰 감사합니다! 리뷰해주신 것 참고해서 TC 설명 개선해보겠습니다. 남은 한주 파이팅입니다! 💪😁

1. 큐를 사용한 BFS(너비 우선 탐색)
2. FIFO(First In First Out)로 노드를 처리함
3. 각 노드를 방문할 때마다:
- 왼쪽과 오른쪽 자식 노드의 위치를 교환
- 교환된 자식 노드들을 큐에 추가하여 다음 노드를 처리함

<Solution 2>
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):
# self.val = val
# self.left = left
# self.right = right
from collections import deque

# Solution 1 (BFS 활용)
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

# 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
32 changes: 32 additions & 0 deletions jump-game/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -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
49 changes: 49 additions & 0 deletions merge-k-sorted-lists/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""
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: O(N log k)
- N은 모든 노드의 총 개수, k는 연결 리스트의 개수
- 힙 연산에 log k 시간이 걸리고, 이를 N번 수행함

Space Complexity: O(k)
- 힙에는 항상 k개의 노드만 저장됨

풀이방법:
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
52 changes: 52 additions & 0 deletions search-in-rotated-sorted-array/KwonNayeon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
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