Skip to content

Commit 3963288

Browse files
authored
Merge pull request #1007 from KwonNayeon/main
[KwonNayeon] Week 10
2 parents 356e622 + b22c9ed commit 3963288

File tree

5 files changed

+263
-0
lines changed

5 files changed

+263
-0
lines changed

course-schedule/KwonNayeon.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
Constraints:
3+
- 1 <= numCourses <= 2000
4+
- 0 <= prerequisites.length <= 5000
5+
- prerequisites[i].length == 2
6+
- 0 <= ai, bi < numCourses
7+
- All the pairs prerequisites[i] are unique.
8+
9+
Time Complexity: O(N + P)
10+
- N: numCourses, P: prerequisites의 길이
11+
12+
Space Complexity: O(N + P)
13+
- 세트의 메모리 사용량이 N과 비례하고 인접 리스트의 크기가 P
14+
- 재귀 호출 스택의 깊이는 최악의 경우 O(N)
15+
16+
풀이방법:
17+
1. prerequisites을 directed graph로 변환
18+
- 각 코스별로 선수과목의 리스트를 저장함
19+
2. DFS를 사용하여 cycle 존재 여부 확인
20+
- visited 배열: 이미 확인이 완료된 노드 체크
21+
- path 배열: 현재 DFS 경로에서 방문한 노드 체크
22+
3. cycle이 발견되면 false, 그렇지 않으면 true 반환
23+
- 현재 경로에서 이미 방문한 노드를 다시 만나면 cycle 있음
24+
- 모든 노드 방문이 가능하면 cycle 없음
25+
"""
26+
class Solution:
27+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
28+
graph = [[] for _ in range(numCourses)]
29+
for course, prereq in prerequisites:
30+
graph[course].append(prereq)
31+
32+
visited = [False] * numCourses
33+
path = [False] * numCourses
34+
35+
def dfs(course):
36+
if path[course]:
37+
return False
38+
if visited[course]:
39+
return True
40+
41+
path[course] = True
42+
43+
for prereq in graph[course]:
44+
if not dfs(prereq):
45+
return False
46+
47+
path[course] = False
48+
visited[course] = True
49+
50+
return True
51+
52+
for course in range(numCourses):
53+
if not dfs(course):
54+
return False
55+
56+
return True
57+

invert-binary-tree/KwonNayeon.py

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
Constraints:
3+
- The number of nodes in the tree is in the range [0, 100].
4+
- -100 <= Node.val <= 100
5+
6+
<Solution 1>
7+
Time Complexity: O(n)
8+
- 각 노드를 한 번씩 방문함
9+
10+
Space Complexity: O(w)
11+
- w는 트리의 최대 너비(width)
12+
13+
풀이방법:
14+
1. 큐를 사용한 BFS(너비 우선 탐색)
15+
2. FIFO(First In First Out)로 노드를 처리함
16+
3. 각 노드를 방문할 때마다:
17+
- 왼쪽과 오른쪽 자식 노드의 위치를 교환
18+
- 교환된 자식 노드들을 큐에 추가하여 다음 노드를 처리함
19+
20+
<Solution 2>
21+
Time Complexity: O(n)
22+
- 각 노드를 한 번씩 방문함
23+
24+
Space Complexity: O(h)
25+
- h는 트리의 높이, 재귀 호출 스택의 최대 깊이
26+
27+
풀이방법:
28+
1. DFS(깊이 우선 탐색)와 재귀를 활용
29+
2. 각 노드에서:
30+
- 왼쪽과 오른쪽 자식 노드의 위치를 교환
31+
- 재귀적으로 왼쪽, 오른쪽 서브트리에 대해 같은 과정 반복
32+
3. Base case: root가 None이면 None 반환
33+
"""
34+
# Definition for a binary tree node.
35+
# class TreeNode:
36+
# def __init__(self, val=0, left=None, right=None):
37+
# self.val = val
38+
# self.left = left
39+
# self.right = right
40+
from collections import deque
41+
42+
# Solution 1 (BFS 활용)
43+
class Solution:
44+
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
45+
if not root:
46+
return None
47+
48+
queue = deque([root])
49+
50+
while queue:
51+
node = queue.popleft()
52+
53+
node.left, node.right = node.right, node.left
54+
55+
if node.left:
56+
queue.append(node.left)
57+
if node.right:
58+
queue.append(node.right)
59+
60+
return root
61+
62+
# Solution 2 (DFS와 재귀 활용)
63+
class Solution:
64+
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
65+
if not root:
66+
return None
67+
68+
root.left, root.right = root.right, root.left
69+
70+
self.invertTree(root.left)
71+
self.invertTree(root.right)
72+
73+
return root

jump-game/KwonNayeon.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Constraints:
3+
- 1 <= nums.length <= 10^4
4+
- 0 <= nums[i] <= 10^5
5+
6+
Time Complexity: O(n)
7+
- n은 배열의 길이만큼 한 번 순회
8+
9+
Space Complexity: O(1)
10+
- 추가 공간 사용 없음
11+
12+
풀이방법:
13+
1. max_reach 변수로 현재까지 도달 가능한 최대 거리 저장
14+
2. 배열을 순회하면서:
15+
- 현재 위치가 max_reach보다 크면 도달 불가능
16+
- max_reach를 현재 위치에서 점프 가능한 거리와 비교해 업데이트
17+
- max_reach가 마지막 인덱스보다 크면 도달 가능
18+
"""
19+
class Solution:
20+
def canJump(self, nums: List[int]) -> bool:
21+
max_reach = nums[0]
22+
23+
for i in range(len(nums)):
24+
if i > max_reach:
25+
return False
26+
27+
max_reach = max(max_reach, i + nums[i])
28+
29+
if max_reach >= len(nums) - 1:
30+
return True
31+
32+
return True

merge-k-sorted-lists/KwonNayeon.py

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
Constraints:
3+
- k == lists.length
4+
- 0 <= k <= 10^4
5+
- 0 <= lists[i].length <= 500
6+
- -10^4 <= lists[i][j] <= 10^4
7+
- lists[i] is sorted in ascending order.
8+
- The sum of lists[i].length will not exceed 10^4
9+
10+
Time Complexity: O(N log k)
11+
- N은 모든 노드의 총 개수, k는 연결 리스트의 개수
12+
- 힙 연산에 log k 시간이 걸리고, 이를 N번 수행함
13+
14+
Space Complexity: O(k)
15+
- 힙에는 항상 k개의 노드만 저장됨
16+
17+
풀이방법:
18+
1. 최소 힙을 사용하여 k개의 정렬된 리스트를 효율적으로 병합하는 알고리즘
19+
2. 각 리스트의 첫 번째 노드를 힙에 넣고 시작함
20+
3. 힙에서 가장 작은 값을 가진 노드를 꺼내서 결과 리스트에 추가
21+
4. 꺼낸 노드의 다음 노드를 다시 힙에 넣음
22+
5. 이 과정을 힙이 빌 때까지 반복함
23+
24+
Note: 이 문제는 풀기 어려워서 풀이를 보고 공부했습니다. 복습 필수
25+
"""
26+
# Definition for singly-linked list.
27+
# class ListNode:
28+
# def __init__(self, val=0, next=None):
29+
# self.val = val
30+
# self.next = next
31+
class Solution:
32+
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
33+
min_heap = []
34+
35+
for i, l in enumerate(lists):
36+
if l:
37+
heapq.heappush(min_heap, (l.val, i, l))
38+
39+
head = point = ListNode(0)
40+
41+
while min_heap:
42+
val, i, node = heapq.heappop(min_heap)
43+
point.next = node
44+
point = point.next
45+
46+
if node.next:
47+
heapq.heappush(min_heap, (node.next.val, i, node.next))
48+
49+
return head.next
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""
2+
Constraints:
3+
- 1 <= nums.length <= 5000
4+
- -10^4 <= nums[i] <= 10^4
5+
- All values of nums are unique.
6+
- nums is an ascending array that is possibly rotated.
7+
- -10^4 <= target <= 10^4
8+
9+
Time Complexity: O(log n)
10+
- Binary Search -> 매 단계마다 탐색 범위가 절반으로 줄어듦
11+
12+
Space Complexity: O(1)
13+
- 추가 공간을 사용하지 않음
14+
15+
풀이방법:
16+
1. Binary Search
17+
- left와 right 포인터로 탐색 범위 지정
18+
- mid가 target인지 먼저 확인
19+
2. 정렬된 부분 찾기
20+
- mid를 기준으로 왼쪽이 정렬되어 있는지 확인
21+
- 정렬된 부분에서 target이 존재할 수 있는 범위를 파악
22+
3. Target 위치 탐색
23+
- 왼쪽이 정렬되어 있고 target이 그 범위 안에 있다면 오른쪽 범위를 줄임
24+
- 그렇지 않다면 왼쪽 범위를 늘림
25+
- 반대의 경우도 동일한 방법 적용
26+
4. Target을 찾지 못한 경우 -1을 반환함
27+
"""
28+
class Solution:
29+
def search(self, nums: List[int], target: int) -> int:
30+
left = 0
31+
right = len(nums) - 1
32+
33+
while left <= right:
34+
mid = (left + right) // 2
35+
36+
if nums[mid] == target:
37+
return mid
38+
39+
if nums[left] <= nums[mid]:
40+
if nums[left] <= target <= nums[mid]:
41+
right = mid - 1
42+
else:
43+
left = mid + 1
44+
45+
else:
46+
if nums[mid] < target <= nums[right]:
47+
left = mid + 1
48+
else:
49+
right = mid - 1
50+
51+
return -1
52+

0 commit comments

Comments
 (0)